是否保证初始化顺序

Is initialization order guaranteed

本文关键字:顺序 初始化 是否      更新时间:2023-10-16

我正在使用类似以下代码部分的东西来进行一些初始化。我知道p<T>::i_的初始化是无序的。我相信h是有序的,所以我应该能够推断它的初始化顺序。假设p的标头包含在h的定义之前,有什么保证p<T>::i_会在h之前初始化吗?

struct helper
{
   template <typename T>
   helper(const T&, int i)
   {
      p<T>::i_::push_back(i);
   }
};
static helper h;

类p的定义如下。

template <typename T>
struct p
{
   static std::vector<int> i_;
};
template <typename T>
std::vector<int> p<T>::i_;

具有静态存储持续时间的对象的初始化顺序在转换单元之间是未定义的,并且在每个转换单元内是顺序的。

在您的特定情况下,情况会更加复杂,因为具有静态存储的对象之一是模板类的静态成员。实际上,这意味着访问成员p<T>::i_的每个翻译单元都将创建符号,并添加适当的初始化代码。稍后,链接器将选择其中一个实例并保留它。即使看起来p<T>::i_是在您的翻译单元中的h之前定义的,您也不知道链接器将保留p<T>::i_的哪个实例,并且该实例可能位于不同的翻译单元,因此顺序无法保证。

一般来说,拥有全局对象是个坏主意,我建议你尝试在没有这些全局的情况下重新设计你的程序。

全局或命名空间范围内的对象是在一个转换单元内自上而下构建的。不同翻译单元之间的全局或命名空间级别的构造顺序没有定义。在转换单元之间安排初始化的最合理方法是将对象包装在合适的访问器函数中,例如:

template <typename T>
something<T>& get() {
    static something<T> values;
    return value;
}

然而,请注意,这在C++03中不是线程安全的(因为C++03无论如何都没有线程的概念)。它在C++11中是线程安全的。

不,不能保证。

然而,你能做的是:

template<typename T>
std::vector<int>& registry() {
    static std::vector<int> reg;
    return reg;
}
...
registry<T>().push_back(i);
...

更好的做法是在创业期间避免做一些过于聪明的事情。

main开始前或结束后的调试是一场真正的噩梦(IMO甚至没有在标准中涵盖100%)。简单的注册是可以的,但永远不要做任何可能失败的事情。

多年来,我从这种方法转向了显式初始化/关闭,并且从未回头。