对象的销毁是否正确发生?
Is the destruction of the objects properly happend?
我在这里阅读了这篇文章:When to use virtual destructors?
我的想法是,每当我们使用 new
或智能指针动态创建对象时,基础 class 应该有一个适当的 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
)?为什么?
- 在两个派生的 classes(在上述特定情况下)的构造函数的成员初始值设定项列表中构造
Base
不是必需的吗?
我正在使用 C++11。
该代码中的 object 指针 实际上不是多态的:*d1Object
的静态类型与其动态类型相同,即 Derived1&
(其他object同理)。
因此,直接销毁它会调用正确的析构函数,~Derived1
。因此一切都很好。以下代码出现问题:
Base* b = new Derived1();
delete b;
这隐式调用了 b->~Base();
。由于 ~Base
不是虚拟的,因此 ~Derived1
不会 被调用,因此您会得到 UB。
std::unique_ptr<Base>
也是如此。然而,对于 std::shared_ptr<Base>
来说 not 是真的,因为 shared_ptr<>
构造函数是模板化的,并且存储了构造它的实际 object 的析构函数。也就是说,以下内容很好并且为 objects:
调用了正确的析构函数
std::shared_ptr<Base> p1{new Derived1{});
std::shared_ptr<Base> p2 = std::make_shared<Derived1>();
至于你关于构造函数的问题,与数据成员的问题相同:即使它们不在初始化列表中,它们仍然按照声明的顺序进行默认初始化,并且在 base [= 的情况下40=]es,从最远到最近的顺序 parent。换句话说,你不能不初始化一个parentclass,它总是会发生。
问题 1:在任何情况下(1、2、3)我是否有未定义的行为?为什么?
提供的代码示例中没有未定义的行为。
如果您尝试持有指向 Base
的指针并通过该指针进行删除,则会出现未定义的行为。在提供的示例中,您知道正在删除的具体 class
问题2:在两个派生的classes的构造函数的成员初始值设定项列表中,构造Base不是必需的(在上面的特定例)?
基础 class 构造函数总是被调用,无论您是否显式调用它。如果没有显式调用,将调用默认构造函数。如果没有默认的、无参数的构造函数并且您不调用特定的构造函数,代码将无法编译。
我在这里阅读了这篇文章:When to use virtual destructors?
我的想法是,每当我们使用 new
或智能指针动态创建对象时,基础 class 应该有一个适当的 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
)?为什么? - 在两个派生的 classes(在上述特定情况下)的构造函数的成员初始值设定项列表中构造
Base
不是必需的吗?
我正在使用 C++11。
该代码中的 object 指针 实际上不是多态的:*d1Object
的静态类型与其动态类型相同,即 Derived1&
(其他object同理)。
因此,直接销毁它会调用正确的析构函数,~Derived1
。因此一切都很好。以下代码出现问题:
Base* b = new Derived1();
delete b;
这隐式调用了 b->~Base();
。由于 ~Base
不是虚拟的,因此 ~Derived1
不会 被调用,因此您会得到 UB。
std::unique_ptr<Base>
也是如此。然而,对于 std::shared_ptr<Base>
来说 not 是真的,因为 shared_ptr<>
构造函数是模板化的,并且存储了构造它的实际 object 的析构函数。也就是说,以下内容很好并且为 objects:
std::shared_ptr<Base> p1{new Derived1{});
std::shared_ptr<Base> p2 = std::make_shared<Derived1>();
至于你关于构造函数的问题,与数据成员的问题相同:即使它们不在初始化列表中,它们仍然按照声明的顺序进行默认初始化,并且在 base [= 的情况下40=]es,从最远到最近的顺序 parent。换句话说,你不能不初始化一个parentclass,它总是会发生。
问题 1:在任何情况下(1、2、3)我是否有未定义的行为?为什么?
提供的代码示例中没有未定义的行为。
如果您尝试持有指向 Base
的指针并通过该指针进行删除,则会出现未定义的行为。在提供的示例中,您知道正在删除的具体 class
问题2:在两个派生的classes的构造函数的成员初始值设定项列表中,构造Base不是必需的(在上面的特定例)?
基础 class 构造函数总是被调用,无论您是否显式调用它。如果没有显式调用,将调用默认构造函数。如果没有默认的、无参数的构造函数并且您不调用特定的构造函数,代码将无法编译。