【问题标题】:Does modifying class member objects in the destructor result in undefined behavior?在析构函数中修改类成员对象会导致未定义的行为吗?
【发布时间】:2017-03-27 10:40:29
【问题描述】:

例如:

struct B { int b_; };
struct D : B
{
    ~D()
    { // D object's lifetime ends here
        d_ = 0;  // (1) undefined behavior?
        b_ = 0;  // (2) undefined behavior also?
    }
    int d_;
};

C++ Standard defines 对于D 类型的对象,当析构函数~D() 调用开始时,它的生命周期结束

我们是否可以将其解释为修改析构函数内的对象(如(1)中所示)会导致未定义的行为?

如果是这样,如果我们修改D的基类子对象,是否同样适用,如(2)?

【问题讨论】:

  • its lifetime ends when the destructor ~D() call starts 不!生命结束后!构造函数结束!
  • @Klaus 不正确。当析构函数调用 starts 时生命周期结束
  • @krzaq:我可以在析构函数中使用它的所有数据成员做所有事情。在达到结束“}”之前没有任何问题。那么为什么你认为生命周期在析构函数开始时结束?
  • 代码很好,原因与struct X { int a; X() { a = 0; } }; 很好的原因基本相同:可以在对象正在构造或销毁时分别从构造函数或析构函数中传递地引用成员。跨度>
  • @LeoHeinsaar:KerrekSB 的示例显示的是赋值,而不是初始化。

标签: c++ language-lawyer destructor undefined-behavior lifetime


【解决方案1】:

两个访问都未定义,它们都很好。

虽然你是对的,当析构函数开始时生命周期结束,你仍然可以以有限的方式使用对象,定义为:

N4140 § 3.8 [basic.life] / 6

同样,在一个生命周期之前 对象已启动,但在对象将占用的存储空间之后 已分配,或者在对象的生命周期结束后,并且 在对象占用的存储空间被重新使用或释放​​之前, 任何引用原始对象的泛左值都可以使用,但仅限于 有限的方式。 对于正在构建或销毁的对象,请参阅 [class.cdtor].

和[class.cdtor]:

N4140 § 12.7 [class.cdtor] /1

对于具有非平凡析构函数的对象,引用任何 析构函数后对象的非静态成员或基类 完成执行会导致未定义的行为。

上面明确指出,只有在析构函数完成后,您才能触摸该对象的成员。

【讨论】:

  • 看起来很彻底,谢谢。我将把问题改写为 (1) 一个问题,以免混淆其他观众。
【解决方案2】:

您展示的所有示例都不是未定义的行为。它们被完美定义。

类实例存在直到析构函数返回。对象的成员不是在调用析构函数之前被销毁,而是在它返回之后。因此,在析构函数中修改类的成员是完全合乎情理的。并且在子类完全销毁之前,超类不会被销毁,因此修改超类的成员也很好。

一般来说,一个对象会被以下过程销毁:

  1. 析构函数被调用。
  2. 类成员以与初始构造相反的顺序被销毁。
  3. 针对对象的超类重复步骤 1 和 2。

(为了简单起见,我忽略了虚拟继承,这里不相关)。

【讨论】:

    猜你喜欢
    • 2017-03-17
    • 2011-03-18
    • 1970-01-01
    • 2020-09-25
    • 2011-01-29
    • 2014-08-11
    • 2016-09-04
    相关资源
    最近更新 更多