C++ 初始化列表是否总是在构造函数代码之前处理?

C++ 初始化列表是否总是在构造函数代码之前处理?,c++,constructor,initialization,C++,Constructor,Initialization,初始化列表是否总是在构造函数代码之前处理 换句话说,以下代码是否总是打印,并且构造的类将具有“已知”作为源的值(如果全局变量something为true) class-Foo{ std::字符串源代码; 公众: Foo():源代码(“”){ std::cout是的,它将按照C++11:12.6.2/10(与C++14中的相同部分,以及C++17中的15.6.2/13)进行: 在非委托构造函数中,初始化按以下顺序进行(我的粗体): 首先,并且仅对于大多数派生类(1.8)的构造函数,虚拟基类按照

初始化列表是否总是在构造函数代码之前处理

换句话说,以下代码是否总是打印
,并且构造的类将具有“已知”作为
的值(如果全局变量
something
true

class-Foo{
std::字符串源代码;
公众:
Foo():源代码(“”){

std::cout是的,它将按照
C++11:12.6.2/10
(与
C++14
中的相同部分,以及
C++17
中的
15.6.2/13
)进行:


在非委托构造函数中,初始化按以下顺序进行(我的粗体):

  • 首先,并且仅对于大多数派生类(1.8)的构造函数,虚拟基类按照它们在基类的有向无环图的深度优先从左到右遍历中出现的顺序进行初始化,其中“从左到右”是派生类基类说明符列表中基类的出现顺序

  • 然后,直接基类按照它们在基说明符列表中出现的声明顺序进行初始化(无论mem初始值设定项的顺序如何)

  • 然后,按照类定义中声明的顺序初始化非静态数据成员(同样,与mem初始值设定项的顺序无关)

  • 最后,执行构造函数主体的复合语句


使用init列表的主要原因是帮助编译器进行优化。非基本类型(即类对象而不是
int
float
等)的init列表通常可以就地构造

如果创建对象,然后在构造函数中分配给它,这通常会导致创建和销毁临时对象,这是低效的

Init列表可以避免这种情况(当然,如果编译器能够做到,但大多数都应该做到)

下面的完整程序将输出7,但这是针对特定编译器(CygWin g++)的,因此它不能保证这种行为,就像原始问题中的示例一样

然而,根据上面第一段中的引文,该标准确实保证了这一点

#include <iostream>
class Foo {
    int x;
    public:
        Foo(): x(7) {
            std::cout << x << std::endl;
        }
};
int main (void) {
    Foo foo;
    return 0;
}
#包括
福班{
int x;
公众:
Foo():x(7){

STD::CUT>是的,C++在调用构造代码之前构造所有成员。

< P>已回答,初始化列表在进入构造函数块之前完全执行。因此在构造函数体中使用(初始化)成员是完全安全的。< /P> 您在接受的答案中做出了一条评论,表示必须引用构造函数参数,但不能引用构造函数块中的成员变量。您没有这样做

您可能错误地认为应该在初始化列表中引用参数而不是成员属性。例如,给定一个具有两个int类型成员(a_u和b_u)的类X,以下构造函数可能定义错误:

 X::X( int a ) : a_( a ), b( a_*2 ) {}
这里可能存在的问题是,初始化列表中元素的构造取决于类中声明的顺序,而不是键入初始化列表的顺序。如果类定义为:

class X
{
public:
   X( int a );
private:
   int b_;
   int a_; 
};
然后,不管您如何键入初始化列表,事实上,b_uu(a_*2)将在a_u初始化之前执行,因为成员的声明首先是b_u,然后是a_u。这将创建一个错误,正如您的代码所认为的(可能取决于)当b_u是a_u值的两倍时,实际上b_u包含垃圾。最简单的解决方案是不引用成员:

 X::X( int a ) : a_( a ), b( a*2 ) {} // correct regardless of how X is declared

避免这个陷阱是建议您不要将成员属性用作其他成员初始化的一部分的原因。

让我想知道为什么人们不首先尝试编译源代码:)@arul:@dehmann可能只有一个编译器。如果该行为是实现定义的,编译将没有帮助。您需要引用标准。是的,只是编译和试用并不能告诉您这是否在任何地方都可以使用。我问这个问题的一个原因是,我似乎记得在构造函数中我应该引用构造函数参数,而不是刚刚初始化的成员变量,如:Foo(std::string str):str_(str){//现在参考str而不是str_}。但这似乎是错误的。我不同意优化是初始化列表的主要原因,而是不能默认构造的基和成员的构造(其类型需要构造函数的参数)。这是一个太复杂的讨论,无法仅在评论部分处理。将不进行上/下投票
 X::X( int a ) : a_( a ), b( a*2 ) {} // correct regardless of how X is declared