对象的销毁是否正确进行?

Usi*_*Cpp 1 c++ polymorphism virtual class c++11

我在这里阅读了这篇文章:什么时候使用虚拟析构函数? 我的想法是,每当我们使用动态new指针或智能指针动态创建对象时,基类都应具有适当的virtual析构函数,以在删除对象时对其进行破坏。

然后,我发现了一些如下代码(简化形式),它错过了virtual析构函数Base

class Base
{
public:
    // some static members
};

class Derived1 final : public Base
{
public:
    // other members
    // default constructor does not construct the `Base` in constructor member intilizer
    Derived1() {};
    virtual ~Derived1() = default;
};
class Derived2 final : public Base
{
public:
    // other members
    Derived2() {}; // default constructor does not construct the `Base`
    ~Derived2() = default;
};

int main()
{
    // creating Derived1 dynamically        // 1
    Derived1 *d1Object = new Derived1{};

    // creating Derived2 dynamically        // 2
    Derived2 *d2Object1 = new Derived2{};

    // creating Derived2 statically         // 3
    Derived2 d2Object2{};

    // clean up
    delete d1Object;
    delete d2Object1;
}
Run Code Online (Sandbox Code Playgroud)

我的问题是:

  • 在任何情况下(1, 2, 3),我都有未定义的行为吗?为什么?
  • Base在两个派生类的构造函数的成员初始化器列表中构造,不是必需的(在上述特定情况下)?

我正在使用C ++ 11。

Kon*_*lph 6

该代码的对象指针实际上不是多态的:的静态类型与*d1Object动态类型Derived1&相同,即(其他对象也是如此)。

因此,销毁它会直接调用正确的析构函数~Derived1。因此,一切都很好。以下代码中出现问题:

Base* b = new Derived1();
delete b;
Run Code Online (Sandbox Code Playgroud)

这隐式调用b->~Base();。而且,由于~Base不是虚拟的,~Derived1没有被调用,你因此得到UB。

的情况也是如此std::unique_ptr<Base>。但是,这不是正确的,std::shared_ptr<Base>因为shared_ptr<>构造函数是模板化的,并存储与其一起构造的实际对象的析构函数。也就是说,以下方法很好,并且可以为两个对象调用正确的析构函数:

std::shared_ptr<Base> p1{new Derived1{});
std::shared_ptr<Base> p2 = std::make_shared<Derived1>();
Run Code Online (Sandbox Code Playgroud)

至于关于构造函数的问题,与数据成员的观点相同:即使缺少初始化程序列表中的数据,它们仍将按照其声明的顺序进行默认初始化,对于基类,则按照大多数情况的顺序进行初始化。距离最近的父母较远。换句话说,您不能初始化父类,它总是会发生。