物体的破坏是否正确发生?

Is the destruction of the objects properly happend?

本文关键字:是否      更新时间:2023-10-16

我在这里阅读了这篇文章:何时使用虚拟析构函数? 我的想法是,每当我们使用new或智能指针动态创建对象时,基类都应该有一个适当的virtual析构函数,用于在删除时销毁对象。

然后我找到了一些如下代码(简化形式(,它错过了Base中的virtual析构函数:

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;
}

我的问题是:

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

我正在使用 C++11。

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

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

Base* b = new Derived1();
delete b;

这隐式地调用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>();

至于你关于构造函数的问题,与数据成员的问题相同:即使它们在初始化器列表中缺失,它们仍然按照它们的声明顺序进行默认初始化,对于基类,则按从最远到最近的父级的顺序进行默认初始化。换句话说,你不能初始化父类,它总是会发生。

问题 1:在任何一种情况下(1、2、3(,我是否有未定义的行为?为什么?

提供的代码示例中没有未定义的行为。 如果要尝试按住指向Base的指针并通过该指针删除,则会出现未定义的行为。在提供的示例中,您知道要删除的具体类

问题 2:在两个派生类的构造函数的成员初始值设定项列表中(在上述特定情况下(中,构造 Base 不是必需的吗?

始终调用基类构造函数,无论是否显式调用它。如果没有显式调用,则将调用默认构造函数。如果没有默认的无参数构造函数,并且您不调用特定的构造函数,则代码将无法编译。