【问题标题】:WinRT - no static constructors?WinRT - 没有静态构造函数?
【发布时间】:2012-09-05 06:32:40
【问题描述】:

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

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

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

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

谢谢

【问题讨论】:

  • 这些都不是 WinRT 特有的,是吗?您只是在问如何在 C++ 中初始化静态数据?能给我举个例子吗?为什么需要静态构造函数来初始化它?为什么不只是...初始化它?
  • 作为一名 c# 开发人员,我习惯于使用静态构造函数,并且我认为 c++ 中有一个等价的 - 但是是的,我只需要实例化和初始化静态数据
  • @DeanChalk 我认为 C++ 没有静态构造函数这样的概念。我不明白为什么普通的构造函数不能完成你需要的工作。为什么不发布一些相关代码。你可能只是犯了一些简单的错误。
  • @jalf 实际上我猜这不是 C++ 问题,而是 C++/CX 问题(因此以某种方式特定于 WinRT),但我不确定,因为 OP 不知道区别或者他确实使用 WRL 使用标准 C++ 和 WinRT。考虑到它拥有的许多其他 .NETism,C++/CX 可能确实有静态构造函数(尽管问题似乎没有)。
  • C++/CX 没有静态构造函数。无论如何,一个明显的答案是“使用更少的静态”:)

标签: c++ windows-8 windows-runtime c++-cx


【解决方案1】:

你在类内部声明静态成员,但你必须在外部定义它们:

// 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();

【讨论】:

  • @DeanChalk 查看我修改后的答案。
  • @Dean Chalk:您不必使用文字来初始化静态 - 您可以使用函数调用的结果。
【解决方案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
    }
  }
};

【讨论】:

    【解决方案3】:

    正如 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 的这一特性。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2011-03-01
      • 1970-01-01
      • 2011-05-29
      • 2012-07-15
      • 1970-01-01
      • 2011-10-09
      • 2011-04-19
      • 1970-01-01
      相关资源
      最近更新 更多