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

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

以下代码

#include <iostream>

struct A {
    A() {
        std::cout << std::endl;
    }
};

struct B {
    static inline A a;
};

int main() {
}

用gcc编译后成功,但用clang编译后由于分段错误而崩溃。是代码不规范还是clang错了?

https://godbolt.org/z/tEvfrW

std::ios_base::Init 上的 Cppreference reads:

The header <iostream> behaves as if it defines (directly or indirectly) an instance of std::ios_base::Init with static storage duration: this makes it safe to access the standard I/O streams in the constructors and destructors of static objects with ordered initialization (as long as #include <iostream> is included in the translation unit before these objects were defined).

您确实在 B::a 之前包含了 <iostream>,但是 B::a 的初始化(B::astatic inline 变量)不是 [= 的一部分51=],所以可以在std::ios_base::Init之前初始化。似乎 Clang(至少某些版本)正是这样做的。这是一个有效的行为。

标准为([basic.start.dynamic]):

  1. Dynamic initialization of a non-local variable with static storage duration is unordered if the variable is an implicitly or explicitly instantiated specialization, is partially-ordered if the variable is an inline variable that is not an implicitly or explicitly instantiated specialization, and otherwise is ordered.

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

  1. Dynamic initialization of non-local variables V and W with static storage duration are ordered as follows:

3.1. If V and W have ordered initialization and the definition of V is appearance-ordered before the definition of W, or if V has partially-ordered initialization, W does not have unordered initialization, and for every definition E of W there exists a definition D of V such that D is appearance-ordered before E, then ...

3.2. Otherwise, if the program starts a thread other than the main thread before either V or W is initialized, it is unspecified in which threads the initializations of V and W occur; the initializations are unsequenced if they occur in the same thread.

3.3. Otherwise, the initializations of V and W are indeterminately sequenced.

3.1 和 3.2 不适用。所以我们有不确定顺序的初始化。

您可以使 B::a 成为非 inline 静态变量或以某种方式强制 std::ios_base::Init 在使用 std::coutfor example:[=54= 之前进行初始化]

struct A {
    A() {
        std::cout << std::endl;
    }

    std::ios_base::Init init;
};