仅在非静态的情况下构造

Only construct if non-static

本文关键字:情况下 静态      更新时间:2023-10-16

我有一个侵入式链表,它在各种上下文中使用——有时被用作全局静态变量,有时被用作普通变量。

当它被用作全局静态变量时,我希望我能避免运行构造函数,因为所有成员都将初始化为零。

当它被用作普通变量时,我希望有一个构造函数来初始化null的成员(两个指针)。

这样做的动机是我有不同的编译单元,并且不能控制调用静态构造函数的顺序。其他编译单元中的一些构造函数正在"挂接"到全局列表中,问题是一个构造函数可能会在构造列表之前使用该列表。

当时的想法是,如果不需要构建列表,那么初始化顺序就没有问题。

只需正常编写默认构造函数,但将其设为constexpr

struct List
{
  constexpr List() : head(nullptr), tail(nullptr) { }
  ...
};

当您定义一个具有静态存储持续时间(即全局)的List对象时,编译器会确保该对象不是动态初始化的,因此在动态初始化阶段,它保证在任何其他构造函数需要它之前发生。

当您声明一个具有自动或动态存储持续时间的变量(即作为本地变量或在堆上)时,构造函数将正常运行并设置两个成员。

这正是像std::mutex这样的类型具有constexpr构造函数的原因,以确保在任何事情都可以尝试使用它们之前对它们进行初始化。

如果您需要C++03解决方案,请将全局设置为本地静态,可以根据需要通过以下函数访问(并初始化):

inline List& global_list()
{
  static List list;
  return list;
}

或者你可以求助于一个涉及第二个构造函数的笨拙解决方案:

struct List
{
  struct no_init_t { };
  static no_init_t no_init;
  List() : head(0), tail(0) { }
  List(no_init_t) { }
  ...
};
List global_list(List::no_init);

第二个构造函数有意不进行初始化,因为全局的成员最初都是零。这意味着,如果另一个翻译单元中的代码在列表的生存期开始之前访问该列表(这在技术上是未定义的行为),它会找到零值的成员,并可以添加到列表中,如果no_init列表构造函数稍后运行,它不会将变量清零,也不会丢失之前添加的数据。这很难看,但应该有效。显然,no_init构造函数应该只用于全局,所以这个解决方案更容易出错。

相关文章: