成员构造函数和析构函数调用的顺序

sbk*_*sbk 113 c++

哦,C++大师,我寻求你的智慧.对我说说标准,告诉我C++是否保证以下程序:

#include <iostream>
using namespace std;

struct A
{
    A() { cout << "A::A" << endl; }
    ~A() { cout << "A::~" << endl; }
};

struct B
{
    B() { cout << "B::B" << endl; }
    ~B() { cout << "B::~" << endl; }
};

struct C
{
    C() { cout << "C::C" << endl; }
    ~C() { cout << "C::~" << endl; }
};

struct Aggregate
{
    A a;
    B b;
    C c;
};

int main()
{
    Aggregate a;
    return 0;
}
Run Code Online (Sandbox Code Playgroud)

永远都会产生

A::A
B::B
C::C
C::~
B::~
A::~
Run Code Online (Sandbox Code Playgroud)

换句话说,成员是否保证按声明的顺序初始化并以相反的顺序销毁?

dir*_*tly 130

换句话说,成员是否保证按声明的顺序初始化并以相反的顺序销毁?

对两者都是.见12.6.2

6初始化应按以下顺序进行:

  • 首先,仅对于如下所述的派生类最多的构造函数,虚拟基类应按它们出现在基类有向无环图的深度优先从左到右遍历的顺序进行初始化,其中"左" -to-right"是派生类base-specifier-list中基类名称的出现顺序.

  • 然后,直接基类应按声明顺序初始化,因为它们出现在base-specifier-list中(无论mem-initializers的顺序如何).

  • 然后,非静态数据成员应按它们在类定义中声明的顺序进行初始化(同样不管mem-initializers的顺序如何).

  • 最后,执行构造函数体的复合语句.[注意:声明顺序的作用是确保以初始化的相反顺序销毁基础和成员子对象. - 尾注]

  • 如果我没记错的话,两者都可以......把它想象成一个堆栈。首先推送,最后弹出。因此,在实例化您的第一个实例时,它会按堆栈顺序推送到内存中。然后,第二个被推过去,第三个被推过去,依此类推。然后,当销毁您的实例时,程序将查找第一个销毁的,最后一个被推送的。但我这样解释可能是错误的,但这是我在做 C/C++ 和 ASM 时学习它的方式。 (2认同)

AnT*_*AnT 29

是的,他们是(非静态成员).初始化(构造)见12.6.2/5,销毁见12.4/6.

  • +1表示这是_non-static_成员.:-) (3认同)

wil*_*ell 9

是的,标准保证对象按照它们创建的相反顺序被破坏.原因是一个对象可能使用另一个对象,因此依赖于它.考虑:

struct A { };

struct B {
 A &a;
 B(A& a) : a(a) { }
};

int main() {
    A a;
    B b(a);
}
Run Code Online (Sandbox Code Playgroud)

如果a是之前破坏b,然后b将举行无效成员引用.通过按照创建它们的相反顺序破坏对象,我们保证正确的破坏.


Chr*_*ung 6

是的,是的.对于成员变量,破坏的顺序总是与构造顺序相反.