class C++ 初始化顺序的静态函数成员中的静态数据成员

Static data member in static function member of class C++ order of initialisation

我有一个宏,用于将键、值添加到注册表映射。 (假设 AddToMap 位于在其他地方定义的全局静态对象上。) 在定义了不同的 classes 之后,AddKey 宏在代码的不同位置被调用(classes 的某种注册表)。代码分成很多.h和.cc文件,依赖关系复杂

我有以下有效的代码:

#define AddKey(key, val)\
namespace NSP_##key {\
class A {\
    public:\
        static bool foo() {\
        static bool dummy = AddToMap(#key, #val);\
}\
};\
static bool dummy_A = A::foo();\
}

`

我想知道静态变量 dummy 是如何创建和初始化的。当我使用 GDB 时,我看到这个 A::add 在 main 或其他任何被调用之前被调用。这是静态变量的预期。

但是,如果我从 class 更改为正常运行,那么代码似乎不再有效并抱怨 "key has already been added"

#define AddKey(key, val)\
namespace NS_##key {\
    static bool A_foo() {\
    static bool dummy = AddToMap(#key, #val);\
}\
static bool dummy_A = A_foo();\
}

我知道 dummy_A 必须是静态的,因为 C++ 中的一个定义规则和 A_foo() 的相同原因。但是,为什么在静态函数中与在 class 的静态成员中静态变量虚拟对象的行为不同?

在 class 中,static 关键字不影响链接,但意味着它独立于 class 对象。无论你有多少次 AddKey(MyClass, hello),只有一个函数 NSP_MyClass::A::foo(),它只调用一次 AddToMap

在 class 或函数之外,static 关键字给出了一个名称内部链接,这意味着包含它的每个编译单元都有自己的名称版本。因此,在您的第二个示例中,每个包含 AddKey(MyClass, hello) 的 *.cc 文件都有一个名为 NS_MyClass::A_foo() 的不同函数。这些函数中的每一个都会尝试调用 AddToMap 一次,给你带来碰撞问题。

使用inline而不是static在头文件中有一个函数定义,但每次都是同一个函数:

#define AddKey(key, val)\
namespace NS_##key {\
    inline bool A_foo() {\
        static bool dummy = AddToMap(#key, #val);\
    }\
    static bool dummy_A = A_foo();\
}