我有一个向量在头部,像这样:
extern std::vector<Foo> g_vector;
在相关的cpp文件中有如下内容:
std::vector<Foo> g_vector;
我也有一个类Bar
,在它的构造函数中,它会添加一些东西到g_vector
,像这样:
Bar::Bar(/* stuff */)
{
// do things
std::cout << g_vector.size() << std::endl;
g_vector.push_back(somefoo);
std::cout << g_vector.size() << std::endl;
}
如果我在一个函数中声明一个Bar
,就像一个理智的人,它似乎工作得很好。但是,如果我想在函数之外声明Bar
,就会发生奇怪的事情。例如,我在MyFile1.cpp和MyFile1.cpp中声明了一个Bar
,并且由于我在Bar中的cout语句,我可以看到Foo
被推入向量,但是当下一个Bar
运行其构造函数时,向量的大小再次为0。换句话说,我的输出是
0
1
0
1
给了什么?只是为了额外的双重确定,我还尝试打印出&g_vector
,以确保它实际上是push_back
进入正确的向量,并且地址都匹配。不管它的价值是什么,这些东西放到向量上的顺序是什么都没关系。我不关心初始化顺序或其他。
不确定问题到底是什么,但我想下面的模式将有助于解决这个问题:定义全局变量的访问器,并将其分配为静态函数变量,如下所示。
头文件:
std::vector<Foo> &getGlobalVector();
在cpp文件:
std::vector<Foo> &getGlobalVector()
{
static std::vector<Foo> s_vector;
return s_vector;
}
此模式的灵感来自Andrei Alexandrescu在现代c++设计中的"泛型单例"实现。
我已经养成了系统地使用这个模式的习惯,每当我在维护现有的应用程序时遇到一个现有的全局变量(或者在极少数情况下,我实际上选择自己使用一个全局变量),它可能有助于消除上述应用程序中一些难以重现的bug。
无论如何,这确实有助于避免任何多次初始化或初始化顺序相关的问题。
全局值初始化顺序未定义
阅读这里的静态初始化失败。
当你在函数中声明Bar
时,g_vector
将在程序运行之前被初始化,因为它承诺在程序运行之前被初始化。如果Bar
是一个全局变量,那么你就有问题了。