C++ 静态成员是否在调用构造函数之前初始化?

C++ 静态成员是否在调用构造函数之前初始化?,c++,static,initialization,member,C++,Static,Initialization,Member,我有一个包含std::map静态成员的类。在实现构造函数体之前,我在相同的转换单元(相同的cpp文件)中初始化它。我的程序没有输出就失败了。我发现了被称为静态初始化顺序失败的问题,但我认为情况可能不是这样 class Test { public: static std::map<std::string, Test*> a; Test(std::string ID) { /* in my complete code (where constructor

我有一个包含std::map静态成员的类。在实现构造函数体之前,我在相同的转换单元(相同的cpp文件)中初始化它。我的程序没有输出就失败了。我发现了被称为静态初始化顺序失败的问题,但我认为情况可能不是这样

class Test {
public:
    static std::map<std::string, Test*> a;
    Test(std::string ID) {
        /* in my complete code  (where constructor
         * implementation and map initialization
         * are in a separate Test.cpp file), this fails, maybe
         * because the map is not initialized at the time
         * the constructor is being called by a sub class of Test */
        a.insert({ID, this});
    }
};
类测试{
公众:
静态std::映射a;
测试(标准::字符串ID){
/*在我的完整代码中(其中
*实现和映射初始化
*在单独的Test.cpp文件中),这可能会失败
*因为当时映射没有初始化
*构造函数正在被测试的子类调用*/
a、 插入({ID,this});
}
};
当我对其他变量进行静态初始化时,构造函数由
Test
子类调用。

是否存在在初始化映射之前调用
Test
的构造函数的场景

这是标准所说的:-


具有静态存储持续时间(basic.stc.static)的对象的存储应在进行任何其他初始化之前进行零初始化(dcl.init)。零初始化和带有常量表达式的初始化统称为静态初始化;所有其他初始化都是动态初始化。POD类型(基本类型)的对象,其静态存储持续时间由常量表达式(expr.const)初始化,应在进行任何动态初始化之前进行初始化。在同一个翻译单元中命名空间范围内定义静态存储持续时间的对象,并动态初始化,其初始化顺序应在其翻译单元中出现的顺序。 <代码> static < /Cord>声明在C++类中定义了一个“属于”对象。指向类本身,而不是从该类创建的对象。 这意味着任何
静态
成员的初始化都应该在Cpp文件中声明

使用以下语法:

std::map<std::string, Test*> Test::a = {};
std::map Test::a={};

所以对于你的问题,没有这样的情况。所有的
静态
成员总是在调用任何类构造函数之前初始化。

解决问题的简单方法是使映射成为某个函数的
静态
局部,该函数返回对它的引用。此函数可以是翻译单元专用函数或
静态
类方法

一般来说,翻译UNOT之间的
静态
全局变量之间的依赖关系是一个坏主意,因为并非所有情况下都完全定义了初始化顺序

在标准下,
静态
局部变量在使用前被初始化一次。请注意,较旧版本的visual studio在多线程初始化方面存在问题,但在较新版本中不存在问题。

“是否存在在以前调用测试构造函数的情况?” 地图已初始化?“当然。所需要的只是有 是一个
Test
的静态实例,位于 地图的定义者。(其中
测试的定义与此无关。重要的是静态
定义了
测试
的实例。)

还有其他可能的场景:一些 例如,其他静态对象使用
测试的本地实例

此问题的通常解决方案是对 地图:

std::map&Test::registry()
{
静态std::仅映射Theoneonly;
只有一个人返回;
}
这将导致在第一次需要时构建地图

您使用的是哪种编译器?不能为指定初始值设定项 类定义中的静态成员,除非该成员是常量和
具有整数或枚举类型。

我认为[basic.start.init]/4是更相关的段落。除非它们不是。不,它们不是。如果在同一转换单元中的静态成员之前定义静态实例,则该实例将在静态成员之前初始化(调用构造函数)。@MikeSeymour-我接受您的细微差别,事实上,如果有人在映射初始化之前声明了静态
测试
对象,然后它将被称为first@NirMH如果他们在不同的翻译单元中定义它,则不会指定首先调用哪个。我使用默认构造函数
mymap={}初始化类的cpp文件中的映射如果我不这样做,我会得到一个链接器错误。另一个问题:在没有执行构造函数代码的情况下,如何构造一个对象?它怎么可能不相关?这就是你应该做的。在您的问题中,您在类定义中进行了初始化;这是不合法的。当构建对象时,将执行构造函数代码。但是构造器代码位于何处(在什么翻译单元中等)是不相关的;重要的是被初始化对象的定义位于何处;除非它与映射的定义位于同一转换单元中,否则不会指定初始化顺序。
std::map<std::string, Test*>& Test::registry()
{
    static std::map<std::string, Test*> theOneAndOnly;
    return theOneAndOnly;
}