我有一个在各种上下文中使用的侵入式链表 - 有时用作全局静态变量,有时我将它用作普通变量。
当它用作全局静态变量时,我希望我是否可以避免让构造函数运行 - 因为无论如何所有成员都将被初始化为零。
当它用作普通变量时,我希望有一个构造函数将成员(两个指针)初始化为 null
。
这样做的动机是我有不同的编译单元并且无法控制调用静态构造函数的顺序。其他编译单元中的一些构造函数正在“ Hook ”到全局列表中,问题是一个构造函数可能在构造列表之前使用它。
这个想法是,如果不需要构建列表 - 那么初始化顺序就没有问题。
最佳答案
只需正常编写默认构造函数,但使其成为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
构造函数应该只用于全局变量,所以这个解决方案更容易出错。
关于c++ - 仅在非静态时构造,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/29209910/