【问题标题】:Static initialization order fiasco for built-in objects/libraries内置对象/库的静态初始化顺序惨败
【发布时间】:2016-04-12 03:40:32
【问题描述】:

如果我有一些静态初始化的变量(在main 开始之前),我是否可以随意使用这些构造函数中的任何内置内容,例如<iostream><vector>

“静态初始化顺序失败”的发生是因为静态变量的初始化顺序(在不同的翻译单元中)未定义。

如果是良性的,比如

std::cout << "Hello" << std::endl;

碰巧依赖<iostream> 中的一些静态变量被提前初始化? (我不是说确实如此,但假设确实如此。)内置库中的这些静态变量在我自己的静态变量之前初始化是什么意思?就像里面说"Person.cpp" 或其他什么。

编辑: Is std::cout guaranteed to be initialized? 被建议作为此问题的副本。但是,我认为我的问题范围更广,因为它询问的是 any 标准内置库,而不仅仅是 <iostream>

【问题讨论】:

  • 我怀疑你必须为每个对象做出决定。我的猜测是标准库中的任何对象都在动态初始化开始之前被初始化,但这只是一个猜测。
  • 为什么你认为vector 有什么静态的东西要初始化?
  • @underscore_d 我从没说过。它可能没有。但我不确定。 (无论是vector 还是任何其他标准库)这就是我问这个问题的原因。

标签: c++


【解决方案1】:

C++ 标准没有对程序在 main 开始之前或 main 完成之后的行为做出强有力的陈述。

根据经验,我发现 C++ 运行时破坏了一些对象(例如用于管理 std::mutex 的资源)的许多问题,这在复杂类型的破坏中造成了死锁。

我会推荐以下静态模式

C++ 按照执行顺序在函数中创建声明为静态的对象。这留下了一个模式,可以确保对象在需要时存在。

   AnObject * AnObject::getInstance() {
       static AnObject a;
       return &a;
   }

这应该被执行以获取全局,并将在调用getInstance() 时发生。

C++ 11 以上

此代码保证是线程安全的,如果多个执行线程到达getInstance,则只有一个将构造对象,其余的将等待。

预 C++ 11

创建此模式会用线程安全问题替换定义不明确的顺序。

幸运的是,可以在 main 中创建一个临界区/互斥体原语,它可以进行仲裁。

在某些操作系统(例如 InitializeCriticalSection 和 Windows)中,这些锁可以在 main 作为静态变量之前安全地创建。

   AnObject * AnObject::getInstance() {
       EnterCriticalSection( &aObjectcrit );
       static AnObject a;
       LeaveCriticalSection( &aObjectcrit );
       return &a;
   }

假设您在调用此函数时或之前已初始化 aObjectcrit。

这种模式的结果是洋葱构造的一种形式,其中对象按照需要的顺序被需要,当程序退出时,它们会按照创建时的相反顺序被销毁。

【讨论】:

    【解决方案2】:

    您混淆了对象 (std::cout) 和类型 (std::vector)。前者被链接问题所覆盖,后者是一种类型。静态初始化适用于对象,但不适用于类型。

    【讨论】:

    • 我没有混淆对象和类型。这似乎不太可能,但如果<vector> 在内部依赖于在构造任何vector<T> 之前初始化的某个静态对象怎么办?或任何其他标准库的类似问题。
    • @Joe:这将是实现中的一个错误。请记住,静态初始化问题的存在是因为没有跨实现解决它的标准方法,但标准库是实现的一部分。它可以使用不可移植的方法,因此即使特定的实现依赖于这样一个静态对象,它也需要确保它被正确初始化。
    猜你喜欢
    • 2016-02-28
    • 1970-01-01
    • 2011-07-15
    • 1970-01-01
    相关资源
    最近更新 更多