C ++初始化:const全局与静态类成员的顺序

时间:2015-02-26 11:04:24

标签: c++ initialization

在以下库代码中:

#include <cmath>

namespace blah {
const double pi=4.0*std::atan(1.0);
}

template <int I>
class ClassB
{
public:
   ClassB() {myval = blah::pi;}
private:
   double myval;
};

template <int I>
class ClassA
{
public:
   static ClassB<I> b;
};

template<int I>
ClassB<I> ClassA<I>::b = ClassB<I>();

template class ClassA<3>;

是在pi的构造函数使用它之前要由其分配给其值4.0*std::atan(1.0)的标准保证的变量ClassB吗?

据我所知,标准pistatic ClassA<I>::ClassB<I> b应该按照在这个单一翻译单元中定义的顺序进行初始化 - 因此pi应该是首先初始化。

但是,在我的实际代码库中使用上面的代码结构,我发现在Clang 3.6编译的代码中,pi在执行ClassB构造函数时等于零,并且仅在此之后初始化为其适当的值。 (正如我期待的那样,GCC 4.8.3首先初始化pi。)

2 个答案:

答案 0 :(得分:3)

简单的答案是否定的。没有保证。如果ClassB<I> ClassA<I>::b = ClassB<I>()不是模板,那么就会有保证,因为两者都在同一个翻译单元中,但如果静态是模板类的成员,则保证不再存在(可能是因为实际的实例化可能在任何翻译单位)。

然而,在这种特殊情况下:为什么获得常数pi的复杂方式。只是:

double const pi = 3.1415926535897932384626433832795;

应该足够了。 (如果您对任何目标计算机有任何疑问,请添加更多数字。但这比获得IEEE最准确的表示所需要的多。)因为这是静态初始化,所以保证在任何动态初始化发生之前发生。

答案 1 :(得分:0)

正如James Kanze所说,答案是否定的,订单无法保证(即使ClassA<3>在翻译单元中明确实例化)。 This answer提供了有关此问题的更多详细信息。

一种解决方案是使用

专门化库.cpp文件中的静态成员变量
template<>
ClassB<3> ClassA<3>::b = ClassB<3>();

而不是使用template class ClassA<3>;实例化模板。

C ++ 03规范。并没有明确说明这一点,但是C ++ 11规范。在这个问题上更清楚:

  

明确专门化的定义   类模板静态数据成员已经订购了初始化。   其他类模板静态数据成员(即隐式地)   或明确实例化的特化)已无序   初始化。

相关问题