C++:全局外部变量"double free or corruption"?



我对在整个程序中一次性使用全局变量很感兴趣。所以我认为实现这一点的最好方法是在头文件中定义它,如下所示:

extern const std::string CONST_STR = "global string";

但这导致了"双重免费或腐败"的运行时错误。删除extern使问题消失。

  1. 有人能解释这种行为吗
  2. AFAIK,如果没有extern定义,每个翻译单元都会有一个CONstrongTR,难道没有办法获得一个完全常量的全局变量吗

解决第一部分和关于丢失extern的其他问题。

const std::string CONST_STR = "global string";

根据C++规则,这与说:相同

static const std::string CONST_STR = "global string";

如果这是在包含文件中,您将在每个翻译单元(TU)中创建不同的字符串。它们自己都能很好地工作,但假设你也在同一个标题中添加了一个函数:

inline void foo() { std::cout << CONST_STR; }

如果<<运算符通过const&获取字符串,则在每个TU中,它将绑定到一个单独的字符串。因此违反了"一个定义规则",并将您置于未定义的行为(UB)。在实践中,它很可能是有效的,但它仍然是UB。

最初的extern形式与此类似,因为看起来相同的字符串文字在不同的TU中也是分开的。

如果只说extern而没有初始化器,那么它就是一个声明,并且将由链接器解析为单个定义。如果你使用一个初始值设定项,那么它就是一个定义。因此,再次在每个TU中创建对象,但使用一个公共名称,期望其他TU访问它。由于必须确保实际只提供一个定义,因此实现免除了责任。

不幸的是,一个定义规则太容易被打破,而且它的大多数形式都明确允许实现不发布任何诊断。实际上,链接器只是从池中随机选择一个定义。双重释放可能是由于为构造函数和析构函数调用发出_atstart_atexit条目引起的,对象本身被融化为一个,然后获得与TU一样多的构造函数和析构函数调用。

对于实现来说,这都是公平的游戏,对于UB来说,任何事情都会发生。

放置定义

const std::string CONST_STR = "global string";

在一个编译单元中(传统的做法是将其放在源文件中)。

在标题中,只写声明:

extern const std::string CONST_STR;

这将确保在整个程序中只有一个版本的字符串。我很惊讶你的链接器没有抱怨你的方式。

最新更新