Base class 没有析构函数,但是 derived class 有。我是否需要寻找与堆无关的任何陷阱?
Base class has no destructor, but derived class does. Do I need to look for any pitfalls that DON'T relate to the heap?
在继承方面,我了解到建议您的 classes 的析构函数是虚拟的,因此除了任何派生的析构函数之外,基础 class 的析构函数也会被正确调用。但是,我想知道在以下场景中是否存在与派生对象相关的堆栈相关问题。
假设我们有一个 Base class 没有析构函数(无论出于何种原因):
class Base{};
和一个确实有析构函数的派生 class:
class Derived : public Base
{
~Derived(){}
};
主要是...:
int main()
{
Derived a;
return 0;
}
我是否 运行 遇到任何来自 Base class 没有析构函数的问题?我最初的猜测是编译器只会为 Base class 生成一个默认的析构函数。同样,我的问题主要与堆栈而不是动态内存有关:是否有任何奇怪的情况我需要注意以避免调用 Derived 析构函数而 Base 析构函数没有被调用?
你的基础 class 有一个隐式析构函数。一切都会好起来的。
虚拟基 class 析构函数用于允许派生构造函数在通过指针或对基 class 的引用进行析构时 运行。所以在你的情况下,这将是不安全的:
void destruct(Base &b) { b.~Base(); }
Derived d; destruct(d);
但这绝对安全:
void destruct(Derived &d) { d.~Derived(); }
Derived d; destruct(d);
您想到的规则是,如果您通过指向其基类型之一的指针删除派生类型的对象,并且该基类型没有虚拟析构函数,则行为是未定义的。此处的代码不会删除任何内容,因此该规则不适用。
为了确保安全,每个析构函数(隐式或显式)至少是以下之一就足够了:
virtual
(对于base classes,如果你需要通过base class指针删除子class实例)
protected
(确保不可能通过基class指针尝试删除)
final
(实际上是class的一个属性,避免了subclasses的全部可能性)。
有一些罕见的边缘情况可以安全地调用析构函数,但它们通常是糟糕设计的标志,如果您设法遇到其中一个,则很容易避免。
顺便说一句,请注意 std::shared_ptr
类型擦除其删除器,因此即使 Base
没有 public 析构函数,std::shared_ptr<Base>
也能正常工作。
在继承方面,我了解到建议您的 classes 的析构函数是虚拟的,因此除了任何派生的析构函数之外,基础 class 的析构函数也会被正确调用。但是,我想知道在以下场景中是否存在与派生对象相关的堆栈相关问题。
假设我们有一个 Base class 没有析构函数(无论出于何种原因):
class Base{};
和一个确实有析构函数的派生 class:
class Derived : public Base
{
~Derived(){}
};
主要是...:
int main()
{
Derived a;
return 0;
}
我是否 运行 遇到任何来自 Base class 没有析构函数的问题?我最初的猜测是编译器只会为 Base class 生成一个默认的析构函数。同样,我的问题主要与堆栈而不是动态内存有关:是否有任何奇怪的情况我需要注意以避免调用 Derived 析构函数而 Base 析构函数没有被调用?
你的基础 class 有一个隐式析构函数。一切都会好起来的。
虚拟基 class 析构函数用于允许派生构造函数在通过指针或对基 class 的引用进行析构时 运行。所以在你的情况下,这将是不安全的:
void destruct(Base &b) { b.~Base(); }
Derived d; destruct(d);
但这绝对安全:
void destruct(Derived &d) { d.~Derived(); }
Derived d; destruct(d);
您想到的规则是,如果您通过指向其基类型之一的指针删除派生类型的对象,并且该基类型没有虚拟析构函数,则行为是未定义的。此处的代码不会删除任何内容,因此该规则不适用。
为了确保安全,每个析构函数(隐式或显式)至少是以下之一就足够了:
virtual
(对于base classes,如果你需要通过base class指针删除子class实例)protected
(确保不可能通过基class指针尝试删除)final
(实际上是class的一个属性,避免了subclasses的全部可能性)。
有一些罕见的边缘情况可以安全地调用析构函数,但它们通常是糟糕设计的标志,如果您设法遇到其中一个,则很容易避免。
顺便说一句,请注意 std::shared_ptr
类型擦除其删除器,因此即使 Base
没有 public 析构函数,std::shared_ptr<Base>
也能正常工作。