在析构函数中修改类成员对象是否会导致未定义的行为?

时间:2016-11-13 19:15:54

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

例如:

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

当析构函数D调用启动时,对于类型为~D()的对象,其生命周期结束C++ Standard defines。< / p>

我们能否解释这意味着修改析构函数内的对象(如(1)中)会导致未定义的行为?

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

2 个答案:

答案 0 :(得分:7)

两种访问都没有定义,它们都完全没问题。

虽然你的生命周期在析构函数启动时结束是正确的,但你仍然可以用有限的方式使用对象,定义如下:

  

N4140§3.8[basic.life] / 6

     

同样,在一生之前   对象已经开始但是在对象占用的存储之后   已经分配,​​或者在对象的生命周期结束后   在重用或释放对象占用的存储之前,   可以使用任何引用原始对象的glvalue,但仅限于   有限的方式。 对于正在建造或毁坏的物体,请参阅   [class.cdtor]

和[class.cdtor]:

  

N4140§12.7[class.cdtor] / 1

     

对于具有非平凡析构函数的对象,请参阅any   析构函数后的对象的非静态成员或基类   完成执行导致未定义的行为。

以上清楚地说明,只有在析构函数完成后才能触及该对象的成员。

答案 1 :(得分:2)

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

在析构函数返回之前,类实例一直存在。对象的成员不会在析构函数被调用之前被销毁,而是在它返回之后被销毁。因此,在析构函数中修改类的成员是完全犹太的。并且在子类被完全销毁之前,超类不会被破坏,所以修改超类的成员也是完美的。

一般来说,对象会被以下过程破坏:

  1. 析构函数被调用。
  2. 班级成员被摧毁,与他们的初步建设方式相反。
  3. 对象的超类重复步骤1和2。
  4. (为了简单起见,我忽略了虚拟继承,这里没有关系。)