什么是C++成语相当于Java静态块?

内容来源于 Stack Overflow,并遵循CC BY-SA 3.0许可协议进行翻译与使用

  • 回答 (2)
  • 关注 (0)
  • 查看 (11)

我有一个静态成员的类,我想运行一些代码来初始化它们(假设这个代码不能转换成一个简单的表达式)。在Java中,我只会这样做

class MyClass {
    static int myDatum;

    static {
        /* do some computation which sets myDatum */
    }
}

除非我错了,否则C ++不允许使用这种静态代码块,对吧?我应该做些什么呢?

我想为以下两个选项解决方案:

  1. 初始化发生在进程加载时(或加载此类的DLL时)。
  2. 初始化发生在类首次实例化时。

对于第二种选择,我想到:

class StaticInitialized {
    static bool staticsInitialized = false;

    virtual void initializeStatics();

    StaticInitialized() {
        if (!staticsInitialized) {
            initializeStatics();
            staticsInitialized = true;
        }
    }
};

class MyClass : private StaticInitialized {
    static int myDatum;

    void initializeStatics() {
        /* computation which sets myDatum */
    }
};

但这是不可能的,因为C ++(目前?)不允许初始化非常量静态成员。但是,至少可以通过表达式将静态块的问题减少到静态初始化的问题......

提问于
用户回答回答于

可以用C ++初始化静态数据成员:

#include "Bar.h"

Bar make_a_bar();

struct Foo
{
    static Bar bar;
};

Bar Foo::bar = make_a_bar();

你可能不得不考虑翻译单元之间的依赖关系,但这是一般的方法。

用户回答回答于

对于#1,如果在进程启动/库加载时确实需要初始化,则必须使用特定于平台的某些内容(例如Windows上的DllMain)。

但是,如果足够让您在与静态执行相同的.cpp文件中的任何代码之前运行初始化,则应该执行以下操作:

// Header:
class MyClass
{
  static int myDatum;

  static int initDatum();
};

// .cpp file:
int MyClass::myDatum = MyClass::initDatum();

这样,initDatum()保证在.cpp执行该文件的任何代码之前被调用。

如果你不想污染类定义,你也可以使用Lambda(C ++ 11):

// Header:
class MyClass
{
  static int myDatum;
};

// .cpp file:
int MyClass::myDatum = []() -> int { /*any code here*/ return /*something*/; }();

不要忘记最后一对括号 - 实际上称为lambda。

至于#2,有一个问题:你不能在构造函数中调用虚函数。你最好在课堂上亲自动手,而不是使用基类:

class MyClass
{
  static int myDatum;

  MyClass() {
    static bool onlyOnce = []() -> bool {
      MyClass::myDatum = /*whatever*/;
      return true;
    }
  }
};

假设这个类只有一个构造函数,那可以工作得很好; 它是线程安全的,因为C ++ 11保证了初始化静态局部变量的这种安全性。

扫码关注云+社区