C++ c++;静态方法中使用的静态无序映射未初始化
我有一些调用静态方法的代码,同一文件中的静态C++ c++;静态方法中使用的静态无序映射未初始化,c++,stl,C++,Stl,我有一些调用静态方法的代码,同一文件中的静态std::unordered_map没有初始化。我知道两个编译单元之间的静态初始化是“未定义”的,并且有很多关于这个主题的问题;但是,当我使用std::vector时,不会出现问题。此外,代码可以执行,但我不明白为什么这些特定的编译顺序不起作用因此,我的问题是: 关于静态变量的静态初始化和动态初始化,还有另一个SO问题(我一直找不到!)。此错误是由于std::undored\u map实际上是一个动态初始化引起的吗 有没有办法让这段代码按照我的预期初始
std::unordered_map
没有初始化。我知道两个编译单元之间的静态初始化是“未定义”的,并且有很多关于这个主题的问题;但是,当我使用std::vector
时,不会出现问题。此外,代码可以执行,但我不明白为什么这些特定的编译顺序不起作用<代码>因此,我的问题是:
SO
问题(我一直找不到!)。此错误是由于std::undored\u map
实际上是一个动态初始化引起的吗std::unordered_map
?实际上,我正在尝试创建一个静态库.lib
或.a
。当我链接静态库时,它通常需要排在最后,因此会发生错误std::vector
和std::无序映射。使用std::vector
,而std::unordered_映射
未初始化(通过bool_映射_初始化
)。通过调用一个函数来迭代std::vector
中的值,以生成std::unordered\u映射,将std::unordered\u映射的初始化更改为显式动态
g++ -std=c++1y -g -c thing.cpp
g++ -std=c++1y -g -c main.cpp
g++ -g main.o thing.o -o main
./main
这将导致浮点异常(内核转储)
错误。通过gdb
,我能够计算出hashtable\u policy.h
trys\u num%\u den代码>其中\uu den==0
。同样使用gdb
,它看起来好像Thing::Things
未初始化
(gdb) break thing.cpp:12
(gdb) run
(gdb) print Thing::Things
No symbol "Things" in specified context.
(gdb) print thing
$1 = (Thing *) 0x618c20
窗口
cl /EHsc /Zi /c main.cpp
cl /EHsc /Zi /c thing.cpp
link /debug main.obj thing.obj
main
在我的实际代码中,这导致了一个非常明显的分段错误;然而,这个例子只是打开了一个弹出窗口,说应用程序失败了。。。我没有做过更好的诊断
代码
thing.cpp
#include<iostream>
#include "thing.hpp"
std::vector<Thing*> Before; // EDIT: added
std::unordered_map<std::string, Thing*> Thing::Things;
std::vector<Thing*> After; // EDIT: added
Thing::Thing(std::string name) : name(name) {
}
bool Thing::Register(Thing *thing) {
std::cout << "no worries, vectors initialized..." << std::endl;
Thing::Before.push_back(thing); // EDIT: added
Thing::After.push_back(thing); // EDIT: added
std::cout << "added to vectors, about to fail..." << std::endl;
Thing::Things[thing->name] = thing;
return true;
}
main.cpp
#include "thing.hpp"
#include <iostream>
ADD_THING(obligatory);
ADD_THING(foo);
ADD_THING(bar);
int main(int argc, char* argv[]) {
std::cout << "before loop" << std::endl;
for (auto thing : Thing::Things) {
std::cout << "thing.name: " << thing.first << std::endl;
}
return 0;
}
#包括“thing.hpp”
#包括
添加内容(强制性);
加上东西(foo);
添加内容(条);
int main(int argc,char*argv[]){
std::cout如注释中所述,没有定义静态初始化顺序。谁知道vector和map之间的区别。也许编译器首先用名称中的偶数个字符初始化类
如果您运行的是c++11
或更高版本,则函数本地项的静态初始化保证是线程安全的。它们将在控件第一次通过声明语句时初始化
// Header
class Thing {
public:
static std::unordered_map<std::string, Thing*>& Things();
static bool Register(Thing* thing);
// CPP
std::unordered_map<std::string, Thing*>& Thing::Things()
{
static std::unordered_map<std::string, Thing*> things;
return things;
}
//头
阶级事务{
公众:
静态std::无序的映射和事物();
静态布尔寄存器(Thing*Thing);
//CPP
std::无序的地图&事物::事物()
{
静态std::无序映射事物;
归还物品;
}
这将在您第一次请求东西时进行初始化,并避免静态初始化的所有潜在随机性。如注释中所述,静态初始化顺序未定义。谁知道向量和映射之间的区别。可能您的编译器在类的na中使用偶数个字符初始化类我先
如果您运行的是c++11
或更高版本,则函数本地项的静态初始化保证是线程安全的。它们将在控件第一次通过声明语句时初始化
// Header
class Thing {
public:
static std::unordered_map<std::string, Thing*>& Things();
static bool Register(Thing* thing);
// CPP
std::unordered_map<std::string, Thing*>& Thing::Things()
{
static std::unordered_map<std::string, Thing*> things;
return things;
}
//头
阶级事务{
公众:
静态std::无序的映射和事物();
静态布尔寄存器(Thing*Thing);
//CPP
std::无序的地图&事物::事物()
{
静态std::无序映射事物;
归还物品;
}
这将在您第一次请求内容时进行初始化,并避免静态初始化的所有潜在随机性。静态初始化很棘手。如前所述,该标准为单个“翻译单元”(通常为.cpp源文件)内的初始化顺序提供了一些保证,但没有任何关于不同翻译单元中的顺序初始化的内容
当您将之前
和之后的向量添加到代码中时,您发现与调用有序映射操作符[]
不同,对向量::推回()的调用
没有使该过程崩溃,并得出结论,即对象在单个翻译单元内被初始化的顺序不正确,这与标准的保证相反。这里有一个隐藏的假设,即由于push_back()
没有导致崩溃,因此向量必须已初始化。事实证明并非如此:对未初始化对象的方法调用几乎肯定会损坏某处的内存,但不一定会导致崩溃。检查是否调用构造函数的更好方法是在调试器,并在包含对象定义的行上设置断点,例如thing.cpp
中std::vector Before
。这将显示初始化将按照标准中的预测进行
如前所述,避免“失败”的最佳选择是“第一次使用时构造”。在示例代码中,这将涉及更改Thing::Things
的任何直接用法,如以下行:
Thing::Things[thing->name] = thing;
对于一个方法,比如说Thing::GetThings()
,它初始化对象并返回对该对象的引用。提供了一个示例,但请注意:虽然它解决了静态初始化问题,但使用作用域静态对象可能会带来更严重的问题:在程序退出时由于
std::unordered_map<std::string, Thing*>& Thing::GetThings()
{
static std::unordered_map<std::string, Thing*>* pThings =
new std::unordered_map<std::string, Thing*>();
return *pThings;
}