【问题标题】:C++ initialisation: order of const global vs static class memberC ++初始化:const全局与静态类成员的顺序
【发布时间】:2015-02-26 11:04:23
【问题描述】:

在以下库代码中:

#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>;

标准保证变量piClassB的构造函数使用之前赋值给它的值4.0*std::atan(1.0)

据我所知,pistatic ClassA&lt;I&gt;::ClassB&lt;I&gt; b 应该按照它们在单个翻译单元中定义的顺序进行初始化 - 因此应该首先初始化 pi

但是,在具有上述代码结构的真实代码库中,我发现在 Clang 3.6 编译的代码中,pi 在执行 ClassB 构造函数时等于零,并被初始化为只有在此之后它的正确值。 (如我所料,GCC 4.8.3 首先初始化 pi。)

【问题讨论】:

    标签: c++ initialization


    【解决方案1】:

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

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

    double const pi = 3.1415926535897932384626433832795;
    

    应该够了。 (如果您对任何目标机器有任何疑问,请添加更多数字。但这超出了获得 IEEE 可能的最准确表示所需的数量。)并且由于这是静态初始化,因此可以保证在之前发生进行任何动态初始化。

    【讨论】:

      【解决方案2】:

      正如 James Kanze 所说,答案是否定的,无法保证顺序(即使 ClassA&lt;3&gt; 在翻译单元中显式实例化)。 This answer 提供了有关该问题的更多详细信息。

      一种解决方案是专门化库 .cpp 文件中的静态成员变量,使用

      template<>
      ClassB<3> ClassA<3>::b = ClassB<3>();
      

      而不是用template class ClassA&lt;3&gt;; 实例化模板。

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

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

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2020-01-31
        • 1970-01-01
        • 2012-02-02
        • 2013-04-13
        相关资源
        最近更新 更多