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映射的初始化更改为显式动态
  • Linux

    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;
    }