【问题标题】:Destructor not invoked when deleting void pointer删除 void 指针时未调用析构函数
【发布时间】:2013-10-10 02:52:13
【问题描述】:

我有 3 节课

class A
{
    A();
    virtual ~A();
}
class B : public A
{
    B();
    ~B();
}
class C
{
    void *obj;
    C() : obj(nullptr) {}
    ~C() { if (obj) delete obj; }
}

当我使用 C 类作为 A 类的任何子类的容器并尝试删除 C 实例时。 A, B 没有调用析构函数是正常的吗?解决办法是什么?

C* instance = new C();
instance.obj = new B();
//Magic
delete instance; // A and B destructor is not called

【问题讨论】:

  • delete 非常具有类型意识。如果你 deletevoid * 它不会知道该对象最初是 C
  • 如果您使用C 作为“A 类的任何孩子”的容器,为什么不能将A * 用于obj 的类型?
  • can't delete a void pointer。它不是有效的 C++,甚至不应该编译。如果是这样,则说明您没有使用真正的 C++ 编译器,并且此问题没有适当标记。
  • @KerrekSB:删除void* 并没有错;如果它不为空,则只是未定义的行为。我的(合理的“真实”)编译器只是发出警告。
  • @MikeSeymour:是的,这样更好。但这是你真的不能忽视的警告之一。可以说,它也是标准中的一些遗留问题。如果唯一允许的值是 NULL,为什么还要允许 void 指针?还不如报废整件事。你仍然可以允许delete nullptr

标签: c++ pointers containers destruction


【解决方案1】:

删除指向不兼容类型(包括void)的指针会产生未定义的行为。

解决办法是什么?

  • 使用正确的类型:使用new 指定的类型,或者基类(如果它具有虚拟析构函数);或
  • 使用std::shared_ptr<void>,从std::shared_ptr<correct_type>初始化:它的删除器会做正确的事。

在这种情况下,您似乎可以简单地存储A* 而不是void*,因为您说它应该是“类A 的任何子类的容器”。

顺便说一句,删除之前不需要检查指针是否为空。

【讨论】:

  • +1 表示shared_ptr<void>。很不错。 (可能也可以从unique_ptr<T> 初始化。)
【解决方案2】:

您删除了void*,所以delete 不知道它是B*,因此无法调用析构函数。如果要在删除时调用析构函数,则必须使用类指针。

例如,是否所有可能是 C 的 obj 的类都扩展 A,然后使用 A*

【讨论】:

    【解决方案3】:

    是的,delete需要具体的类型。

    【讨论】:

      猜你喜欢
      • 2014-12-30
      • 1970-01-01
      • 2010-11-09
      • 2012-03-13
      • 2021-04-04
      • 1970-01-01
      • 2013-10-01
      • 2011-03-20
      • 2010-10-15
      相关资源
      最近更新 更多