C++标准中成员原地初始化与初始化列表的优先级规则及代码疑问
成员原地初始化与初始化列表的优先级规则
首先直接给你明确答案:在C++11及之后的标准中,构造函数的初始化列表优先级高于成员的原地初始化,这个规则在C++标准的[class.base.init]章节(类基类初始化相关部分)有明确规定。
具体规则细节
当类的构造函数在初始化列表中显式初始化某个非静态数据成员时,该成员的原地初始化表达式会被直接忽略,完全不会执行。换句话说,初始化列表的显式初始化是“覆盖”了原地初始化的——这不是歧义,是标准明确划定的优先级顺序。
对你的示例代码的分析
看你写的Baz结构:
struct Baz { Baz() : foo(5.0f) {} // 初始化列表显式初始化foo Bar bar; Foo foo = Foo(3); // 原地初始化,会被忽略 Bar bar2; };
当你在main里创建Baz baz时,执行流程是这样的:
- 执行
Baz的构造函数,优先处理初始化列表里的foo(5.0f),调用Foo的float版本构造函数,完全跳过foo = Foo(3)这个原地初始化代码。 - 然后按类成员的声明顺序,初始化
bar和bar2(它们用默认构造函数完成初始化)。
所以你的代码里Foo(3)根本没被调用,自然不会抛出std::runtime_error,程序能正常运行。
关于编译器警告的问题
Visual Studio 2017没给出警告,是因为这是标准允许的合法行为,不属于编译错误。不过有些编译器支持额外的警告选项来提醒这种“原地初始化被覆盖”的情况,比如Clang的-Winitializer-overrides,但VS2017默认没开启这类警告,你可以去编译器的警告设置里找找类似的选项来开启提示。
内容的提问来源于stack exchange,提问作者Rudolfs Bundulis
相关产品推荐
相关产品推荐

