以下代码
#include <iostream>
struct A {
A() {
std::cout << std::endl;
}
};
struct B {
static inline A a;
};
int main() {
}
使用GCC 编译后成功,但在使用 Clang 编译后因分段错误而崩溃。是代码不标准还是叮当错了?
https://godbolt.org/z/tEvfrW
Cpp首选项对std::ios_base::Init
如下:
标头
<iostream>
的行为就像它(直接或间接(定义具有静态存储持续时间的std::ios_base::Init
实例一样:这使得访问静态对象的构造函数和析构函数中的标准 I/O 流变得安全有序初始化(只要在定义这些对象之前#include <iostream>
包含在转换单元中(。
您确实在B::a
之前包含<iostream>
,但B::a
的初始化(B::a
static inline
变量(不是有序初始化的一部分,因此可以在std::ios_base::Init
之前初始化。似乎Clang(至少某些版本(正是这样做的。这是一种有效的行为。
标准如下([basic.start.dynamic](:
如果具有静态存储持续时间的非局部变量是隐式或显式实例化的专用化,则动态初始化是
- 无序的;如果变量是不是隐式或显式实例化的内联变量,则动态初始化是部分有序的,否则是有序的。
因此,std::ios_base::Init
实例的初始化是有序的,B::a
的初始化是部分有序的。
具有
- 静态存储持续时间的非局部变量
V
和W
的动态初始化顺序如下:3.1.如果
V
和W
有有序初始化,并且V
的定义在W
定义之前是外观有序的,或者如果V
有部分有序的初始化,W
没有无序初始化,并且对于W
的每个定义E
都存在一个定义D
V
使得D
在E
之前是外观有序的, 然后。。。3.2. 否则,如果程序在初始化
V
或W
之前启动主线程以外的线程,则未指定初始化V
和W
在哪些线程中进行;如果初始化发生在同一线程中,则初始化是未排序的。3.3. 否则,
V
和W
的初始化将不确定地排序。
3.1 和 3.2 不适用。所以我们有不确定的顺序初始化。
您可以在使用std::cout
之前将B::a
设置为非inline
静态变量或以某种方式强制std::ios_base::Init
初始化,例如:
struct A {
A() {
std::cout << std::endl;
}
std::ios_base::Init init;
};