c++ - C++11 中的延迟初始化顺序

标签 c++ c++11 language-lawyer static-order-fiasco

考虑以下代码,分为三个编译单元:

a.h:

struct A
{
    void Register(const char* s);

    const char* m_s[10];
    int m_i = 0;
};

A& GetA();

a.cpp:

#include "a.h"
#include <stdio.h>

void A::Register(const char* s)
{
    m_s[m_i++] = s;
}

A& GetA()
{
    static A instance;
    return instance;
}

int main(int argc, char* argv[])
{
    A& a = GetA();
    int n = a.m_i;
    for (int i = 0; i < n ; ++i)
        printf("%s\n", a.m_s[i]);
    return 0;
}

b.cpp:

#include "a.h"
struct B
{
    B() { GetA().Register("b"); }

    static B* instance;
};
B* B::instance = new B;

c.cpp:

#include "a.h"
struct C
{
    C() { GetA().Register("c"); }

    static C* instance;
};
C* C::instance = new C;

代码使用 gcc (-std=c++11) 构建并运行良好,产生输出:

c
b

现在,引用cppreference.com :

Deferred dynamic initialization

It is implementation-defined whether dynamic initialization happens-before the first statement of the main function (for statics) or the initial function of the thread (for thread-locals), or deferred to happen after.

If the initialization of a non-inline variable is deferred to happen after the first statement of main/thread function, it happens before the first odr-use of any variable with static/thread storage duration defined in the same translation unit as the variable to be initialized. If no variable or function is odr-used from a given translation unit, the non-local variables defined in that translation unit may never be initialized (this models the behavior of an on-demand dynamic library). However, as long as anything from a TU is odr-used, all non-local variables whose initialization or destruction has side effects will be initialized even if they are not used in the program.

注意 a.cpp 并不知道 BC 的存在,B< 的唯一交互 & CAGetA()A::Register() 的调用构建各自的实例。

据我所知,BC 实例未使用 ODR,当然也不是来自 main()'翻译单位。他们的初始化显然有副作用,但在我看来,不能保证这个初始化会在进入 main() 之前发生,或者在 main() 打印注册的字符串 - 或者根本没有。

所以 - 最后 - 我的问题是:BC 实例是在 main( ) 打印注册字符串符合标准,而是 gcc 的实现定义行为?

如果是标准保证的,怎么保证?

最佳答案

Is the fact that the B and C instances are initialised before main() prints the registered strings due not to the standard, but instead to gcc's implementation-defined behaviour?

标准保证。报价中最相关的部分:

If no variable or function is odr-used from a given translation unit, the non-local variables defined in that translation unit may never be initialized

因为 b.cppc.cpp 都没有使用函数和变量,所以它们的静态变量可能未初始化(关于动态初始化)和因此它们初始化的副作用可能不可见。


在实践中,我希望翻译单元静态链接时显示的初始化行为,以及动态加载(共享库)时可能出现的非初始化行为。但这两者都没有得到标准的保证,因为它没有指定共享库的行为方式。

关于c++ - C++11 中的延迟初始化顺序,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/45210561/

相关文章:

c - 指针相等是否意味着整数相等?

通过 Schwartz 计数器进行 C++ 静态初始化

c++ - 更改从 OpenSceneGraph 上的 dxf 文件读取的节点颜色

c++ - 在 Windows 中运行应用程序实例中打开文件(C++)

c++ - 之后填充 std::unique_ptr

c++ - 可变参数模板复杂继承生成

c++ - C++17是基于C17的吗?

c++ - 声明嵌套命名空间 `std` 是否合法 C++?

c++ - 在 C++11 中将 fstream 引用作为函数参数传递

c++ - 不正确的类型转换 - 类型转换或未定义行为的使用