静态数据成员初始化顺序

Static data member initialization order

本文关键字:顺序 初始化 数据成员 静态      更新时间:2023-10-16

在一个翻译单元中考虑下面的代码:

class C {
private:
    struct Init {
        Init() {
            /* compute data once here */
        }
    };
    static const Init& i;
    static int data[];
public:
    /* interface for reading data */
};
const C::Init& C::i = Init();
int C::data[200];
    C::i总是在C::data之后初始化,不管两者定义的顺序如何?
  1. 这个解决方案是最优雅的计算静态数据一次?

int C::data[200] is zero-initialized,即静态初始化。静态初始化在动态初始化之前。由于C::Init::Init()不是一个常量表达式,所以C::i是动态初始化的,必须在 C::data之后

详情见3.6.2。

非法引用:

具有静态存储时间的变量[…]在进行任何其他初始化之前,应该进行零初始化。[…零初始化和常量初始化一起称为静态初始化;其他所有初始化都是动态初始化。静态初始化应在任何动态初始化之前执行。

C::data在这里没有初始化,所以顺序不重要。

较短的解决方案是使用静态函数和虚拟变量:

class C {
private:
    static void Init() {
        /* compute data once here */
    }
    static bool data_init_helper;
    static int data[];
public:
    /* interface for reading data */
};
bool C::data_init_helper = (C::Init(), false);
int C::data[200];

是否C::i总是在C::data之后初始化,无论C::data的顺序如何两者的定义?

如果它们在同一编译中定义,则保证顺序

这个解决方案是最优雅的计算静态数据一次?

。如果您真的必须让它保持静态,那么一个更好的方法(并防止可能的静态初始化顺序惨败)是这样做:

struct someDataStr
{
  int data[200];
};
someDataStr& AccessData()
{
  static someDataStr *ptr = NULL;
  if ( NULL == ptr )
  {
    ptr = new someDataStr;
    // initialize value
  }
  return *ptr;
}

如果它不是静态的,那么使用依赖注入,并将包含数据的对象传递给使用它的所有类。