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

Does modifying class member objects in the destructor result in undefined behavior?

本文关键字:未定义 析构函数 修改 成员对象      更新时间:2023-10-16

例如:

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++标准定义了对于D类型的对象,当析构函数~D()调用开始时,其生命周期结束

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

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

这两个访问都是未定义的,它们都是完全可以的。

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

N4140§3.8 [basic。生活[6]

同样,在对象的生命周期之前对象已启动,但在该对象将占用的存储空间之后或在对象的生命周期结束后在对象占用的存储空间被重用或释放之前,任何指向原始对象的全局值都可以使用,但只能在有限的方法。关于正在构建或销毁的对象,请参见(class.cdtor) .

和类。cdtor]:

N4140§12.7 [class。cdtor]/1

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

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

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

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

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

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

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