我有一个在各种上下文中使用的侵入式链表 - 有时用作全局静态变量,有时我用它作为普通变量。
当它被用作全局静态变量时,我想如果我可以避免让构造函数运行 - 因为所有成员都会被初始化为零。
当它被用作普通变量时,我希望有一个构造函数将成员(两个指针)初始化为null
。
这样做的动机是我有不同的编译单元,并且无法控制调用静态构造函数的顺序。其他编译单元中的一些构造函数是"挂钩"进入全局列表,问题是一个构造函数可能在构造之前使用该列表。
这个想法是,如果不需要构建列表 - 那么初始化顺序就没有问题。
答案 0 :(得分:4)
只需正常编写默认构造函数,但将其设为constexpr
。
struct List
{
constexpr List() : head(nullptr), tail(nullptr) { }
...
};
当您使用静态存储持续时间(即全局)定义List
对象时,编译器会确保对象未动态初始化,因此可以保证在动态初始化阶段任何其他构造函数需要它之前。
当您声明具有自动或动态存储持续时间的变量(即作为局部变量或在堆上)时,构造函数将正常运行并设置两个成员。
这正是std::mutex
等类型具有constexpr构造函数的原因,以确保在任何可以尝试使用它们之前对它们进行初始化。
如果您需要C ++ 03解决方案,可以使全局变为本地静态,可以根据需要通过函数访问(和初始化):
inline List& global_list()
{
static List list;
return list;
}
或者您可以使用涉及第二个构造函数的klugey解决方案:
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
构造函数应该只用于全局变量,所以这个解决方案更容易出错。