Dpp*_*Dpp 5 c++ destructor delete-operator
如果基类没有虚拟析构函数(例如为了避免 vtable 条目)并且派生类只有基本属性,那么当基类的指针被删除时,它是否会释放 new 分配的所有内存?我知道派生类的析构函数不会被调用,但我想知道整个对象分配的内存是否会被释放?我还假设在派生指针上调用删除将释放整个内存空间。
另外,如果它不释放派生类的内存部分,那么在相同的情况下,它如何使用基类中的虚拟析构函数来知道要释放多少内存?
例子:
class Base {
public:
int a;
int b;
Base() {}
~Base() {}
};
class Derived : public Base {
public:
int c;
int d;
Derived() {}
~Derived() {}
};
int main() {
Base *p = new Derived();
delete p; // is memory allocated for Derived freed?
}
Run Code Online (Sandbox Code Playgroud)
这是未定义的行为,所以任何事情都有可能发生。引用标准 [expr.delete]:
\n\n\n在第一种选择(删除对象)中,如果要删除的对象的静态类型与其动态类型不同,则静态类型应是要删除的对象的动态类型的基类,并且\n静态类型应具有虚拟\n析构函数,否则行为\n未定义。
\n
只是不要那样做。
\n我认为了解实际发生的情况是一个好主意,同时了解为什么该标准有该要求。
\n在您的简单情况下,在典型的实现中,无论如何都会释放内存。那是因为operator delete会打电话free(p)。由于Base是 的第一个非虚拟基类Derived,因此它恰好位于分配的内存块的开头。并且由于free必须通过自己的簿记了解分配块的大小(作为 C 函数,它不知道类型大小),因此它将释放整个块。
但是,由于Base没有虚拟析构函数,delete p因此是根据*p(即Base)的静态类型解析的。因此,正如您似乎意识到的那样,它不会调用 的析构函数Derived。如果Derived有任何重要的成员或基类,它们也不会被破坏,因此它们管理的任何资源都会被泄漏。
当类有虚拟析构函数时,释放内存的工作就委托给析构函数。原因是,虽然free知道确定块的大小,但仍然需要有指向块开头的指针。在一般情况Base下可以处于任意偏移量,因此析构函数将负责在释放指针之前调整指针。这还增加了对单独析构函数的需求,该析构函数可以在不实际释放内存的情况下析构对象;例如,作为另一个派生类型的子对象,或作为显式析构函数调用。我们不要参与讨论。当您将析构函数标记为虚拟时,编译器会为您处理所有这些事情。DerivedDeriveddelete[]
最重要的是,该标准没有描述所有这些实现细节,而是将它们留给\xe2\x80\x94um\xe2\x80\x94 实现。当删除非虚拟基地仍然可以时,他们可以制定一些合理的标准;但相反,他们采用了简单明确的“你有一个虚拟析构函数,那么就可以了,否则就不行”规则。
\n