如何删除没有dstructor的派生类的对象

时间:2016-07-16 04:30:27

标签: c++ compiler-warnings derived-class

鉴于此计划:

struct Base
{
  virtual void f() {}
};

struct Derived:public Base
{
};

int main()
{
  Derived* c = new Derived;
  delete c;
}

gcc-4.4 -Wall很好,但gcc-5.2 -Wall发出警告:删除具有非虚析构函数的多态类类型'Derived'的对象可能会导致未定义的行为[-Wdelete-non-virtual-dtor]

我看到了the discussion on deleting a base pointer,但就我而言,它是派生对象。我认为这是一个gcc bug,但显然是GNU doesn't think so。反正有没有改变基类定义去除警告?

3 个答案:

答案 0 :(得分:3)

海湾合作委员会完全有权发出警告。为什么?因为除非您声明Derivedfinal,否则某人完全有可能创建源自MoreDerived的{​​{1}}类型。此时,删除Derived指针可能非常无效。

Derived添加virtual析构函数没有真正的缺点。是的,析构函数将是一个虚拟调用。但这很难成为性能瓶颈。

答案 1 :(得分:1)

virtual ~Base() {}添加到Base会修复警告。

所以会将final添加到Derived。

class Derived final : public Base
{
    ...
};

将向Derived添加虚拟析构函数。

class Derived : public Base
{
public:
    virtual ~Derived() {}

    ...
};

此外,如果您不打算以多态方式使用Derived,则可以私下继承它。这不会阻止警告,但您永远不能将派生指针分配给Base指针,因此永远不能通过Base指针删除Derived。

class Derived : private Base
{
    ...
};

答案 2 :(得分:0)

C ++标准[expr.delete]第3段[ISO / IEC 14882-2014]声明以下内容:

在第一个备选方案(删除对象)中,如果要删除的对象的静态类型与它的动态类型不同,则静态类型应为要删除的对象的动态类型的基类,而静态类型应具有虚拟析构函数或行为未定义。在第二种选择(删除数组)中,如果要删除的对象的动态类型与静态类型不同,则行为是不确定的。

请勿通过指向具有非虚拟析构函数的基类类型的指针删除派生类类型的对象。相反,应使用虚拟析构函数定义基类。通过没有虚拟析构函数的类型的指针删除对象会导致未定义的行为。 在这种兼容解决方案中,Base的析构函数具有显式声明的虚拟析构函数,从而确保多态删除操作会导致行为明确。

struct Base {
  virtual ~Base() = default;
  virtual void f();
};

struct Derived : Base {};

void f() {
  Base *b = new Derived();
  // ...
  delete b;
}

如果使用以下链接,则可以找到更多信息:https://wiki.sei.cmu.edu/confluence/display/cplusplus/OOP52-CPP.+Do+not+delete+a+polymorphic+object+without+a+virtual+destructor