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

C++ 修改析构函数中的类成员对象是否会导致未定义的行为?,c++,language-lawyer,destructor,undefined-behavior,lifetime,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()调用启动时,其生存期结束 我们是否可以将其解释为修改析

例如:

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()
调用启动时,其生存期结束

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


如果是这样,那么如果我们修改
D
的基类子对象(如(2)中所示),是否也适用同样的情况?

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

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

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

  • 调用析构函数
  • 类成员被破坏,其顺序与初始构造相反
  • 对对象的超类重复步骤1和2

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

    访问都不是未定义的,它们都很好

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

    N4140§3.8[基本寿命]/6

    同样,在一个 对象已启动,但在对象将占用的存储之后 已分配,或在对象的生存期结束后 在重新使用或释放对象占用的存储之前, 引用原始对象的任何glvalue都可以使用,但只能在 有限的方式。有关正在构建或销毁的对象,请参见 [class.cdtor]

    和[class.cdtor]:

    N4140§12.7[类别cdtor]/1

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


    上面清楚地指出,只有在析构函数完成后,您才能接触该对象的成员。

    当析构函数~D()调用开始时,它的生存期结束。
    否!生命结束后!构造函数结束了@克劳斯,这是不对的。当析构函数调用时,生存期结束starts@krzaq:我可以使用析构函数的所有数据成员执行析构函数中的所有操作。在到达结束“}”之前,它没有任何问题。那么,为什么您认为生命周期在析构函数开始时结束呢?代码基本上是好的,原因与
    struct X{int a;X(){a=0;}很好:当对象分别在构造函数或析构函数中进行构造或销毁时,可以引用成员。@LeoHeinsaar:KerrekSB的示例显示赋值,而不是初始化。看起来很彻底,谢谢。我将重新措辞这个问题,使之成为一个问题,以免混淆其他观众。