考虑以下示例:
#include <iostream>
class Base
{
public:
Base() { std::wcout << L"Base cons" << std::endl; }
~Base() { std::wcout << L"Base des" << std::endl; }
};
class Derived : public Base
{
public:
Derived() { std::wcout << L"Derived cons" << std::endl; }
~Derived() { std::wcout << L"Derived des" << std::endl; }
};
int main()
{
Base * derived = new Derived;
std::wcout << L"Deleting..." << std::endl;
delete derived; // Base::~Base() is not virtual so only Base::~Base() is called
return 0;
}
// Ouput
// Base cons
// Derived cons
// Deleting...
// Base des
由于Base :: ~Base()不是虚拟的,当删除对象“derived”时,只会执行Base :: ~Base()。如果我们不调用Derived :: ~Derived(),它不会是内存泄漏吗?当然,通过将Base :: ~Base()解构器标记为虚拟,可以很容易地解决这个问题,但是想要破坏基础派生类而不是派生类的场景是什么?
(我的理解是,一旦调用了基类析构函数,派生对象就不再处于可用状态了)
我意识到C ++是为效率而设计的 - “只为你需要付出代价” - 所以我真的只是想了解为什么声明派生类不需要虚拟基类解构器(以避免固有的内存)没有清理派生类的泄漏)
提前感谢您的见解。
答案 0 :(得分:2)
执行delete derived
并不一定是内存泄漏,其中derived
的类型为Base*
。因为当Base
没有虚拟析构函数时,这是未定义行为。任何事情都可能发生,包括你期望发生的事情。
请注意,unique_ptr<Base>
的值可能会从unique_ptr<Derived>
复制而出现这种情况。所以这是一种情况,当这个特定的智能指针不那么聪明时。值得记住。
但是,shared_ptr
是安全的,因为shared_ptr
原始指针保存在控制块中并用于删除。
关于标题中的问题,
“什么时候不想要派生类的解构器执行?
......只有当一个人根本不想要对象破坏时才会这样。
我能想到的唯一例子可能是记录器对象。
关于问题文本末尾的问题,
“我真的只是想了解为什么声明派生类不需要虚拟基类解构器
...这是不同的问题。
作为一个具体的例子,使用Microsoft的COM技术,每个COM类继承的IUnknown
接口都没有虚拟析构函数。它不需要因为任何COM对象在其引用计数变为零时自毁。并且自毁代码可以访问派生程度最高的类。
答案 1 :(得分:1)
您不希望虚拟析构函数出现的唯一情况是不需要虚拟析构函数的情况。基本上是一个自制的预言。
如果没有可能使用指向其超类的指针来销毁对象,并且该对象没有其他虚拟方法,那么不声明虚拟析构函数会生成更高效的代码。
答案 2 :(得分:0)
如果派生类没有添加任何内存(例如只更改行为),则可以通过这种方式节省一些CPU周期(因为没有任何内容可以泄漏&#39;)。
可能不是一个好主意 - 让编译器进行这样的优化。