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

问题描述:

哦,C++大师,我寻求你的智慧。讲standardese给我,并告诉我,如果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; 
} 

总是会产生

A::A 
B::B 
C::C 
C::~ 
B::~ 
A::~ 

换句话说,被成员保证按声明的顺序进行初始化和反摧毁订购?

+7

这是一个相当普遍的原因,当类变得越来越大而且不可思议时,就会产生微妙的错误。当你有50个数据成员,并且在构造器初始化列表中初始化它们时,可以很容易假定构造的顺序是初始化器列表中的顺序。毕竟,代码编写者已经小心地列出了这个列表......不是吗? – Permaquid 2010-02-13 05:06:42

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

对两者都是。见12.6.2

初始化应在 下列顺序进行:

  • 首先,并且仅用于 最派生 类的构造如下所述,虚拟基 类应按照 的顺序进行初始化,它们出现在深度优先的 从 的有向无环图的左到右遍历中: 类,其中“从左到右”是 基类 中的名称的顺序 base-specifier-list中派生类中的名称。

  • 然后,直接 基类应在 声明的顺序,因为它们出现在 基符列表(不管 的MEM-初始化的顺序)进行初始化。

  • 然后,非静态数据成员应 初始化中,他们在类定义 声明 顺序(再次不管 MEM-初始化的顺序)。

  • 最后,执行构造函数 的 复合语句。 [注意: 声明命令的授权为 确保基本和成员子对象 以 初始化的相反顺序销毁。末端注]

+0

如果我没有记错的话,对两者都是这样... 把它想象成一个堆栈。先推,最后一搏。因此,在实例化第一个实例时,它会按堆栈顺序存入内存。然后,第二个被推倒,第三个被推倒,等等。然后,当销毁你的实例时,程序将查找第一个要销毁的实例,最后一个被推送。 但我可能是这样解释错误,但这是我在做C/C++和ASM时学到的。 – 2010-02-12 19:03:13

是的,是的。对于成员变量,销毁顺序总是与构造顺序相反。

是的,他们是(非静态成员)。初始化(构造)见12.6.2/5,破坏见12.4/6。

+2

+1,注意这是针对_non-static_成员的。 :-) – 2010-02-12 18:48:50

是,标准的保障对象在创建它们相反的顺序得到破坏。原因是一个对象可能使用另一个对象,因此依赖于它。试想一下:

struct A { }; 

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

int main() { 
    A a; 
    B b(a); 
} 

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