9

我有一段代码结构如下:

a.cpp:  
    #include "b.hpp"  
    const unsigned a =  create(1);


b.cpp:
    map<int, string> something; // global variable
    unsigned create(unsigned a){
        something.insert(make_pair(a, "somestring"));
        return a;
    }

现在,这抛出了一个段错误,valgrind 说该地图尚未创建。它是如何工作的,我应该如何改变它?

4

4 回答 4

11

C++ 没有定义程序启动期间构建全局变量的顺序。a可以在构造之前先初始化something,这会导致上述问题。当您开始构建依赖于正在初始化的其他全局变量的全局变量时,您会遇到经典的静态初始化顺序 fiasco

解决上述情况的一种简单方法是制作something静态并将其移动到您的create函数中。

unsigned create(unsigned a)
{
    static map<int, string> something;
    something.insert(make_pair(a, "somestring"));
    return a;
}

这将保证something在第一次调用时创建create

于 2013-10-27T13:59:47.857 回答
9

所有全局变量都是在进入 main() 之前创建的,但是它们在不同翻译单元之间的构造顺序并没有被 c++ 标准指定。它们在同一个翻译单元中的构造顺序是按照规范的顺序。

您可以形成由标准保证的东西。像这样的东西:

map<int, string>& mymap(){
    static map<int, string> something;
    return something;
}

unsigned create( unsigned a ) {
    mymap().insert(make_pair(a, "somestring"));
    return a;
}

在第一次调用函数 mymap() 时创建地图。

于 2013-10-27T13:58:05.307 回答
3

标准未定义来自不同翻译单元(即位于不同 *.cpp 文件中)的全局变量的初始化顺序。因此,依靠它是undefined behaviour。也可以看看:

于 2013-10-27T13:57:29.043 回答
2

创建全局变量(即命名空间范围内的变量)的顺序指定为:

  • 它们在翻译单元中出现的顺序
  • 未指定,从一个翻译单元到另一个翻译单元

这是带有模块的语言不会遇到的问题,但不幸的是 C++ 中的一个常见问题。使用函数局部静态变量,可以在第一次使用时进行初始化,这通常可以解决这个问题。

静态本地示例:

int func(int a) {
    static std::map<int, int> m;
    return m[a] = m.size();
}
于 2013-10-27T14:34:24.150 回答