C++11中构造函数初始化列表与默认初始化的行为是否符合标准?
C++11类成员初始化顺序与默认成员初始化器的合规性问题
首先看示例代码:
#include <iostream> struct foo { foo() = default; foo(int x): v1{x} {} int v1 = 0; int v2 {v1}; void print() const { std::cout<<"v1:"<<v1<<" v2:"<<v2<<std::endl; } }; int main() { const auto bar1 = foo(); bar1.print(); // prints v1:0 v2:0 const auto bar2 = foo(42); bar2.print(); // prints v1:42 v2:42 }
已知bar1.v1通过默认初始化器完成初始化,bar2.v1由构造函数初始化列表赋值,其默认初始化器被忽略。疑问点:bar2.v2使用了构造函数初始化后的v1值,该行为是否符合C++标准?
结论:该行为完全符合C++11及后续版本的标准
核心依据是类非静态成员的初始化顺序规则:
- 不管成员是通过构造函数初始化列表初始化,还是使用默认成员初始化器(即类定义中直接写的
=0或{v1}这类初始化器),所有非静态数据成员的初始化顺序严格按照它们在类定义中的声明顺序执行,与初始化器的来源无关。
针对bar2对象的创建过程,具体执行步骤:
- 调用构造函数
foo(int x),首先执行初始化列表中的v1{x},将v1赋值为42(此时v1的默认初始化器=0被覆盖,属于标准允许的行为)。 - 按照声明顺序,接下来初始化
v2:由于构造函数初始化列表未指定v2的初始化方式,因此使用它的默认成员初始化器{v1}。此时v1已经完成初始化,值为42,所以v2被正确初始化为42。
再验证bar1的逻辑:
- 默认构造函数执行时,先按声明顺序初始化
v1(使用默认初始化器=0),再初始化v2(使用{v1},此时v1值为0,故v2也为0),与输出结果一致。
C11标准的[class.base.init]/13条款明确规定了这一初始化顺序规则,后续C版本(C14、C17等)也延续了这一规则。
内容的提问来源于stack exchange,提问作者auzn
相关产品推荐
相关产品推荐

