基类没有析构函数,但派生类有析构函数。我是否需要寻找与堆无关的任何陷阱?

Base class has no destructor, but derived class does. Do I need to look for any pitfalls that DON'T relate to the heap?

本文关键字:析构函数 寻找 任何 陷阱 是否 派生 基类      更新时间:2023-10-16

在继承方面,我知道建议类的析构函数是虚拟的,因此除了任何派生析构函数之外,还可以正确调用基类的析构函数。但是,我想知道在以下情况下是否存在与派生对象相关的堆栈相关问题。

假设我们有一个没有析构函数的基类(无论出于何种原因):

class Base{};

以及一个确实具有析构函数的派生类:

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

而且主要...:

int main()
{
  Derived a;
  return 0;
}

我是否遇到基类没有析构函数的任何问题?我最初的猜测是编译器只会为 Base 类生成一个默认析构函数。同样,我的问题主要与堆栈而不是动态内存有关:为了避免调用派生析构函数而 Base 析构函数不被调用,我是否需要注意任何奇怪的场景?

您正在考虑的规则是,如果通过指向派生类型的一个基类型的指针删除该对象,并且该基类型没有虚拟析构函数,则行为是未定义的。此处的代码不会删除任何内容,因此该规则不适用。

为了确保安全,每个析构函数(隐式或显式)至少是以下之一就足够了:

  • virtual(如果需要通过基类指针删除子类实例,则用于基类)
  • protected(确保无法尝试通过基类指针删除)
  • final(实际上是类的一个属性,以避免子类的全部可能性)。

在少数情况下,可以安全地调用析构函数,但它们通常是设计不良的标志,如果您设法遇到其中一个,则很容易避免。

顺便说一句,请注意,std::shared_ptr类型擦除其删除器,因此即使Base没有公共析构函数,std::shared_ptr<Base>也可以工作。

基类有一个隐式析构函数。一切都会好起来的。

虚拟基类析构函数用于允许派生构造函数在通过指针或对基类的引用进行析构时运行。因此,在您的情况下,这将是不安全的:

void destruct(Base &b) { b.~Base(); }
Derived d; destruct(d);

但这将是完全安全的:

void destruct(Derived &d) { d.~Derived(); }
Derived d; destruct(d);