【问题标题】:Static string initialization order issue静态字符串初始化顺序问题
【发布时间】:2020-03-21 08:42:07
【问题描述】:

我在头文件中有extern const 字符串声明,它在源文件中定义:

// a.h
extern const std::string base;

// a.cpp
const std::string base = "base";

然后我在另一个头文件中还有一个extern const字符串,这个字符串的定义使用第一个字符串的定义:

// b.h
extern const std::string usage;

// b.cpp
const std::string usage = base + " str";

在应用程序启动时出现此错误:

动态链接库 (DLL) 初始化例程失败。

我将调试器附加到应用程序,引发以下异常:

抛出异常:读取访问冲突。这是 nullptr。

这是在b.cpp 中向base 抛出的。所以我收集到这是静态初始化顺序的问题。但在我的生成文件中,我在 b.obj 之前列出了 a.obj,所以我不明白为什么会发生这种情况。

请注意,我只在 Windows 上收到此错误。 Linux 很好。

一种补救方法是在头文件中定义base

// a.h
const std::string base = "base";

// a.cpp

这是唯一的解决方案吗?还是有更好的办法?

【问题讨论】:

  • 考虑将base 放入返回局部静态变量的函数中,请参阅:blog.mbedded.ninja/programming/languages/c-plus-plus/…
  • 遗憾的是,这是 Windows 上经常出现的问题(尤其是使用 MSVC)。请不要使用非 POD 外部全局变量,因为它会导致很多问题(不仅在 Windows 上)。此外,请注意,如果这是一个编译时常量,则使用 C++20 constexpr 字符串或 C++17 constexpr std::string_view 可能会有所帮助。

标签: c++ windows dll dynamic-linking static-initialization


【解决方案1】:

您可以使用#pragma init_seg控制初始化顺序

指向c++的指针默认初始化放置在.CRT$XCU部分(在.CRT$XCA__xc_a.CRT$XCZ__xc_z之间)

所以解决方案可以是下一个

// a.cpp
#pragma warning(disable : 4075)
#pragma init_seg(".CRT$XCU1")

const std::string base = "base";

// b.cpp
#pragma warning(disable : 4075)
#pragma init_seg(".CRT$XCU2")

const std::string usage = base + " str";

所以把base".CRT$XCU1"usage".CRT$XCU2" 这保证base 将在usage 之前初始化

【讨论】:

  • 感谢您的信息,我不知道这个,我用过它,它就像魅力一样!无论如何,在这种情况下使用它是否常见?因为我从来没有听说过这个解决方案。另外,如果我在多个源文件中需要base,我是否应该在每个文件中使用相同的".CRT$XCU2"?或者我需要使用".CRT$XCU3"等?
  • @bb8 - 你需要了解它在内部是如何工作的。函数initterm 是如何工作的。当您声明需要初始化的全局变量时 - 编译器分配内部变量(_PVFV 类型 - 指向调用对象构造函数的函数的指针。crt 声明 __xc_a__xc_z 变量并放置它在特殊部分 - 并调用 initterm(&__xc_z, &__xc_z)。查看 crt\src\vcruntime\initializers.cppvcruntime 中的其他文件也查看映射文件
  • @bb8 - 如果我需要在多个源文件中使用 base,我应该在每个文件中使用相同的 ".CRT$XCU2" 吗? - 是的,可以使用 ".CRT$XCU3" - 没有不同 - 主要是 A-Z 顺序中的部分名称必须在 ".CRT$XCU1" 之后 - 所以 2 或 3 - 没有不同,当然最好不要在 1 之后创建额外的部分,如果不需要。所以使用".CRT$XCU2"
【解决方案2】:

不确定为什么标题提到了静态字符串初始化,并且可能这种行为取决于所使用的编译器,但是对于 vs2017,您应该在 b.cpp 文件中包含 a.h 头文件。它对我有用。谢谢。

【讨论】:

    猜你喜欢
    • 2010-09-25
    • 2019-09-17
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2020-01-31
    • 2021-07-12
    相关资源
    最近更新 更多