2015-12-10 99 views
4

我有一个宏,我用它来向注册表映射添加键值。 (假设AddToMap位于全局静态对象上,并在其他地方定义了一些其他对象。) 在定义了不同的类(某种类的注册表)之后,在代码中的各个位置调用AddKey宏。代码分为许多具有复杂依赖性的.h和.cc文件。C++类的静态函数成员中的静态数据成员初始化顺序

我有下面这段代码的工作原理:

#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();\ 
} 

`

我想知道的是如何创建和初始化静态变量假人。当我使用GDB时,我发现这个A :: add在main或main之前被调用,如果被调用。这是对静态变量的期望。

但是,如果我从类更改为函数,则代码似乎没有工作了,并抱怨说,“密钥已经被添加”

#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()的相同原因。但为什么静态函数中的静态变量虚拟行为与静态类中的静态成员时不同?

+1

你在头文件扩展'AddKey'? – aschepler

+0

是的。有一个在cc文件中扩展的GetValue,AddKey在头文件中展开。 –

回答

1

在一个类中,关键字static不影响链接,但表示它独立于类对象。无论您有多少次AddKey(MyClass, hello),只有一个功能NSP_MyClass::A::foo(),它只需要调用AddToMap一次。

在类或函数之外,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();\ 
} 
+0

这似乎工作顺利。内联似乎确保它是跨板的单实例,毕竟.cc文件是链接的。谢谢 –