问题描述
class Base
{
public:
~Base() {}
};
class Derived : public Base
{
public:
Derived() {}
virtual void foo() {}
};
假设您创建了一个 Derived
类的堆分配对象,并使用 delete
关键字将其删除,例如:
int main()
{
Derived *d = new Derived();
delete d;
}
使用 -Wall -Wdelete-non-virtual-dtor -Werror
标志编译此代码会抛出一个错误,这完全没有问题,因为它最终可能会导致 UB。演示here。
显然,调用 d
对象的析构函数是导致编译器错误的原因,因为以下代码具有相同的结果(至少在 CLANG 上,GCC 对以下代码没有问题):
int main()
{
Derived d;
d.~Derived();
}
但是如果我在堆栈上创建一个简单的对象,CLANG 和 GCC 都没有编译器错误:
int main()
{
Derived d;
}
我们都知道 Derived
类的析构函数是在 main
函数的末尾调用的,但是为什么在这种情况下没有错误呢?
解决方法
当一个对象有自动存储期或者是一个类的成员时,不需要考虑多态性。在给定的代码中,左值 d
不能引用更多派生的对象。因此,调用 Derived::~Derived
总是正确的,不需要警告。