在作为静态成员包含在另一个类中的类的构造函数中使用 cout

Using cout in the constructor of a class that is included in another class as a static member

本文关键字:cout 构造函数 另一个 静态成员 包含      更新时间:2023-10-16

以下代码

#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::astatic inline变量(不是有序初始化的一部分,因此可以在std::ios_base::Init之前初始化。似乎Clang(至少某些版本(正是这样做的。这是一种有效的行为。

标准如下([basic.start.dynamic](:

如果具有静态存储持续时间的非局部变量是隐式或显式实例化的专用化,则动态初始化是
  1. 无序的;如果变量是不是隐式或显式实例化的内联变量,则动态初始化是部分有序的,否则是有序的。

因此,std::ios_base::Init实例的初始化是有序的,B::a的初始化是部分有序的。

    具有
  1. 静态存储持续时间的非局部变量VW的动态初始化顺序如下:

3.1.如果VW有有序初始化,并且V的定义在W定义之前是外观有序的,或者如果V有部分有序的初始化,W没有无序初始化,并且对于W的每个定义E都存在一个定义DV使得DE之前是外观有序的, 然后。。。

3.2. 否则,如果程序在初始化VW之前启动主线程以外的线程,则未指定初始化VW在哪些线程中进行;如果初始化发生在同一线程中,则初始化是未排序的。

3.3. 否则,VW的初始化将不确定地排序。

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;
};