我目前正在用 C++ 编写一些 WinRT 自定义控件,我的编译器/智能感知告诉我不允许使用静态构造函数。
我需要设置一些静态数据,并且可以使用私有 bool 实例标志,并且在我的类的第一次实例化时,我可以创建静态数据等。(有效地实现相同的目标)。
但是,也许我错过了一些东西,因为这似乎有点啰嗦。
WinRT/c++ 中静态构造的规范替代方法是什么
谢谢
我目前正在用 C++ 编写一些 WinRT 自定义控件,我的编译器/智能感知告诉我不允许使用静态构造函数。
我需要设置一些静态数据,并且可以使用私有 bool 实例标志,并且在我的类的第一次实例化时,我可以创建静态数据等。(有效地实现相同的目标)。
但是,也许我错过了一些东西,因为这似乎有点啰嗦。
WinRT/c++ 中静态构造的规范替代方法是什么
谢谢
您在类内部声明静态成员,但必须在外部定义它们:
// 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();
C++ 不支持静态构造函数。大多数情况下,您应该使用Joachim Pileborg 的回答中所示的静态初始化。我建议您适应执行静态初始化的惯用 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
}
}
};
正如 Joachim Pileborg 在他的回答中演示的那样,全局变量可以有一个动态初始化程序,它可以用作 C++ 和 C++/CX 中的“静态构造函数”的一种形式。请注意,您可以使用 lambda 表达式来保持本地初始化,例如
int Foo::bar = [](){ return 123; }();
但是,如果可能,建议您不要这样做,原因有两个。首先,动态初始化全局变量的顺序仅部分指定。如果您有一个动态初始化程序,它依赖于另一个源文件中定义的其他全局变量,您可能会遇到麻烦。
其次,更重要的是,Windows 运行时组件是一个 DLL,全局变量的动态初始化作为 DLL 初始化的一部分发生,这发生在调用 DLL 的入口点时。正如 MSDN 在 的文档中所指出的DllMain
,“在 DLL 入口点中可以执行的操作存在严重限制。” 如果您在 Internet 上搜索“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 的此功能。