8

以下代码

#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

4

1 回答 1

7

Cppreferencestd::ios_base::Init 读取

标头的<iostream>行为就好像它(直接或间接)定义了一个具有静态存储持续时间的实例:这使得在具有有序初始化std::ios_base::Init的静态对象的构造函数和析构函数中访问标准 I/O 流变得安全(只要包含在定义这些对象之前的翻译单元)。#include <iostream>

您确实包含<iostream>before B::a,但B::a(可变)的初始化不是有序初始化的一部分B::a因此可以在 before 初始化。似乎 Clang(至少某些版本)正是这样做的。这是一个有效的行为。static inlinestd::ios_base::Init

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

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

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

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

3.1。如果VW有有序的初始化并且 的定义V在 的定义之前是有序的W,或者如果V有部分有序的初始化,W没有无序的初始化,并且对于 的每个定义EW存在这样的定义D,它在 的定义之前是有序的,然后 ...VDE

3.2. V否则,如果程序在初始化或初始化之前启动了主线程以外的线程W,则未指定初始化VW发生的线程;如果它们发生在同一个线程中,则初始化是无序的。

3.3. V否则,和的初始化W是不确定的。

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

您可以在使用之前创建B::a一个非inline静态变量或以某种方式强制std::ios_base::Init初始化std::cout例如

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

    std::ios_base::Init init;
};
于 2020-07-05T08:18:13.307 回答