3

我目前正在用 C++ 编写一些 WinRT 自定义控件,我的编译器/智能感知告诉我不允许使用静态构造函数。

我需要设置一些静态数据,并且可以使用私有 bool 实例标志,并且在我的类的第一次实例化时,我可以创建静态数据等。(有效地实现相同的目标)。

但是,也许我错过了一些东西,因为这似乎有点啰嗦。

WinRT/c++ 中静态构造的规范替代方法是什么

谢谢

4

3 回答 3

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();
于 2012-09-12T09:25:24.193 回答
2

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
    }
  }
};
于 2012-09-12T10:24:18.287 回答
1

正如 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 的此功能。

于 2012-09-14T18:04:27.590 回答