我有兴趣在整个程序中只使用一个全局变量。所以我认为实现这一点的最好方法是像这样在头文件中定义它:
extern const std::string CONST_STR = "global string";
但这导致了“双重释放或损坏”运行时错误。
删除 extern
使问题消失。
- 谁能解释一下这种行为?
- AFAIK,如果没有
extern
定义,每个翻译单元都会有一个 CONST_STR,难道没有办法获得一个完全 const 的全局变量吗?
最佳答案
解决第一部分和有关丢失 extern 的其他问题。
const std::string CONST_STR = "global string";
根据 C++ 规则,这等同于说:
static const std::string CONST_STR = "global string";
如果这是在包含文件中,您将在每个翻译单元 (TU) 中创建不同的字符串。它们本身都可以正常工作,但假设您还在同一 header 中添加了一个函数:
inline void foo() { std::cout << CONST_STR; }
如果<<
运算符通过 const&
获取字符串, 在每个 TU 中,它将绑定(bind)到一个单独的字符串。因此违反了“一个定义规则”并使您陷入未定义的行为(UB)。在实践中它很可能有效,但它仍然是 UB。
原文extern
形式与此类似,因为看起来相同的字符串文字在不同的 TU 中也是分开的。
如果你只说extern
没有初始化器,它是一个声明,将由链接器解析为单个定义。如果您使用初始值设定项,那么它就是一个定义。因此,该对象再次在每个 TU 中创建,但使用公共(public)名称,期望其他 TU 访问它。由于您必须确保实际只提供一个定义,因此实现免除了责任。
不幸的是,单一定义规则太容易被打破,而且它的大多数形式明确允许实现不发出任何诊断。实际上,链接器只是从池中随机选择一个定义。 double free 可能是由于发出 _atstart
引起的和 _atexit
构造函数和析构函数调用的条目,对象本身融合为一个,然后获得与 TU 一样多的构造函数和析构函数调用。
对于实现来说,一切都是公平的,至于 UB,一切皆有可能。
关于c++: "double free or corruption"用于全局外部变量?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/17344999/