如果派生类仅包含自动变量成员,是否有必要具有虚拟驱动器

Is it necessary to have virtual destructor if the derived class only contains automatic variable members?

本文关键字:是否 驱动器 虚拟 成员 派生 包含自 变量 如果      更新时间:2023-10-16
struct base
{
    base(){}
    ~base() { cout << "base destructor" << endl; }
};
struct derived : public base
{
    derived() : base() { vec.resize(200000000); }
    ~derived() { cout << "derived destructor" << endl; }
    vector<int> vec;
};
int main()
{
    base* ptr = new derived();
    delete ptr;
    while (true)
    {
    }
}

由于删除操作而导致的上述代码泄漏未调用派生对象的驱动器。但是...

struct base
{
    base() {}
    ~base() { cout << "base destructor" << endl; }
};
struct derived : public base
{
    derived() : base() {}
    ~derived() { cout << "derived destructor" << endl; }
    int arr[200000000];
};
int main()
{
    base* ptr = new derived();
    delete ptr;
    while (true)
    {
    }
}

在第二种情况下,尽管仅调用基本驱动器,但内存并未泄漏。因此,我假设如果我所有的成员都是自动变量,那么没有基本破坏者是安全的吗?派生类中的" ARR"成员不会在未调用派生对象的驱动器时不会超出范围?幕后发生了什么事?

是!

我看到您正在思考"实际上",即可能错过什么破坏。考虑到您派生的班级的破坏者不仅仅是您写的攻击者的身体;在这种情况下,您还需要考虑成员的破坏,并且您的建议可能不会破坏矢量(因为常规非虚拟破坏您的对象甚至都不知道有派生的部分需要考虑(。向量具有动态分配的内容,将被泄漏。

但是,我们甚至不需要走那么远。程序的行为是不确定的,一段时间的故事结束。优化器可以根据您的代码有效做出假设。如果不是这样,您可以并且应该期望发生奇怪的sh!那是因为C 是一种抽象,汇编很复杂,您与该语言签订了合同。

,如果曾经通过指向该基础的指针删除派生对象,则必须在基类中拥有虚拟破坏者。否则该程序的行为是不确定的。在任何其他情况下,都不需要拥有虚拟驱动器。这是无关紧要的。

不必让内存泄漏并仍然调用UB。如果您的派生类并不小,内存泄漏是一种预期的UB。示例:

#include <iostream>
class  Field {
public:
    int *data;
    Field() : data(new int[100]) {} 
    ~Field() { delete[] data; std::cout << "Field is destroyed"; }
};
class Base {
    int c;
};
// Derived class, contains a non-trivial non-static member                 
class Core : public Base 
{
    Field A;
};
int main()
{
    Base *base = new Core;
    delete base;  // won't delete Field
}

他的C 标准,[Expr.delete],第3款(2014 Edition(

在第一个替代方案(删除对象(中,如果静态类型 要删除的对象与其动态类型不同,即静态 类型应为要为对象的动态类型的基类 已删除,静态类型应具有虚拟破坏者或 行为是不确定的。在第二个替代方案(删除数组(中 要删除的对象的动态类型与其静态类型不同, 行为不确定。

实际上,如果基类是微不足道的,那么所有字段都是微不足道的,并且派生的类不包含非静态或非平凡的成员,可能会争辩说这些类是平等的,但是我尚未找到方法通过标准证明它可能是IB而不是UB。