单个TU中内联变量的静态初始化顺序

9

我知道这个问题已经被问了很多遍,但这似乎是一个稍微不同的变化,我无法解决。

考虑以下代码:

#include <cstdio>

struct TestValue;

inline const TestValue* v_ptr = nullptr;

struct TestValue {
    static const TestValue v1;

    TestValue() {
        v_ptr = this;
        printf("TestValue Initialized at %p\n", this);
    }
};

struct CallTest {
    CallTest() {
        printf("CallTest Initalized at %p\n", this);
        printf("v_ptr = %p\n", v_ptr);
    }
};

const inline TestValue TestValue::v1{};
const inline CallTest ct{};



int main() {}

我正在使用C++17或更高版本,它增加了对extern、静态初始化内联变量的支持。我试图理解当使用inline修饰符“out of line”时关于初始化顺序的保证。请注意,v1被声明为TestValue的静态变量,然后在ct之前但在其定义内联。出乎意料的是(至少对我来说),在使用Clang 14.0.3时,程序输出:

CallTest Initalized at 0x404059
v_ptr = (nil)
TestValue Initialized at 0x404068

如果我将v1TestValue中移出,使其在ct前的同一行声明和定义,那么就会得到预期的输出结果。
TestValue Initialized at 0x404059
CallTest Initalized at 0x404068
v_ptr = 0x404059

我比较自信地认为第二个例子会保证先输出TestValue。但第一个例子呢?
我不确定提前声明v1,然后稍后内联定义它的合法性,但仅是这样似乎没问题:https://eel.is/c++draft/dcl.inline#note-2 至于顺序,我理解v1和ct应该是“部分有序”的:因为它们是内联的https://eel.is/c++draft/basic.start.dynamic#1 然后,由于它们中至少有一个是部分有序的(另一个不是无序的),它们将按照其定义的顺序进行初始化:https://eel.is/c++draft/basic.start.dynamic#3.1 也许我误读了部分有序和无序的定义?v1没有被部分有序吗,因为内联说明符在定义中稍后出现 - 即顺序仅适用于声明时的内联说明符?在这种情况下,我仍然看不出它如何变得无序;另一种可能性是有序的,这也行得通。另外指定内联是需要修复ODR违规的,因此似乎它正在做某些事情。(我从上述情况中发现了这个错误,但TestValue和CallTest及其各自的定义被分成多个头文件,CallTest头文件包括TestValue)。
我还发现GCC尊重v1和ct的定义顺序,而与上面相同,Clang总是先初始化ct。

extern const TestValue v1; const inline TestValue v1{}; extern const inline CallTest ct{};

这初始化先进行v1。我不明白为什么,如果v1是一个静态类变量,它为什么会与普通的extern变量具有不同的初始化顺序。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接