我目前正在用c ++编写一些WinRT自定义控件,而我的编译器/ intellisense告诉我不允许使用静态构造函数。
我需要设置一些静态数据,并且我可以使用私有bool实例标志,并且在我的类的第一个实例化中我可以创建静态数据等。(有效地实现相同的事情)。
然而,也许我错过了一些东西,因为这看起来有点啰嗦。
WinRT / c ++中静态构造的规范替代方法是什么
由于
答案 0 :(得分:6)
您在类中声明了静态成员,但您必须在外部定义它们:
// In header file
class Foo
{
static int bar;
static int bar2;
static int init_bar3() { return 123; }
};
// In source file
int Foo::bar;
// Define and intiailize
int Foo::bar2 = 5;
// For more complicated initialization
int Foo::bar3 = Foo::init_bar3();
答案 1 :(得分:2)
C ++不支持静态构造函数。大多数情况下,您应该使用Joachim Pileborg's answer中所示的静态初始化。我建议你适应那种习惯性的C ++执行静态初始化的方式,而不是试图用C#风格编写C ++。
但是,如果你真的需要C ++中的C#样式静态构造函数,你可以伪造它们:
class Foo {
public:
Foo() {
static_constructor();//call must appear in every constructor
}
Foo(Bar bar, Baz baz) {
static_constructor();//call must appear in every constructor
}
private:
static void static_constructor() {
static bool run = false;
if( !run ) {
run = true;
//your logic goes here
}
}
};
答案 2 :(得分:1)
正如Joachim Pileborg在他的回答中所说,全局变量可以有一个动态初始化器,可以在C ++和C ++ / CX中用作“静态构造函数”的一种形式。请注意,您可以使用lambda表达式来保持初始化本地,例如
int Foo::bar = [](){ return 123; }();
但是,如果可能,建议您不要这样做,原因有两个。首先,仅部分指定动态初始化全局变量的顺序。如果你有一个依赖于另一个源文件中定义的其他全局变量的动态初始化器,你可能会遇到麻烦。
其次,更重要的是,Windows运行时组件是一个DLL,全局变量的动态初始化作为DLL初始化的一部分发生,这在DLL的入口点被调用时发生。正如MSDN在DllMain
的文档中指出的那样,“在DLL入口点可以做什么有严重的限制。”如果您在互联网上搜索“DllMain”,您会发现许多资源描述在DLL初始化期间做任何令人兴奋的事情可能引起的问题。
值得注意的是,禁止您执行任何可能导致加载其他DLL的操作。这意味着,通常,您不能直接或间接使用未在DLL中定义的任何Windows运行时类型,因为可能尚未加载定义它们的DLL。我已经调试了几个挂起,这些挂起是由动态初始化期间完成的异乎寻常工作引起的死锁造成的。
因此,作为替代方案,将全局变量封装在函数中......
class Foo {
public:
static int bar() {
static int value = [](){ return 123; }();
return value;
}
};
...并使用Foo::bar()
代替Foo::bar
。首次输入函数时,块范围静态变量初始化一次。请注意,如果您从多个线程使用Foo::bar
,则可能需要同步初始化; C ++ 11要求初始化是线程安全的,但Visual C ++还没有(从Visual C ++ 2012开始)支持C ++ 11的这个特性。