内联初始化静态const类成员的初始化顺序保证

时间:2019-10-10 07:07:17

标签: c++ c++11 initialization static-members static-order-fiasco

说我有一个static const int类成员变量。它是在类定义中直接初始化的,但是在.cpp中没有定义(可以使用,因为它没有被使用)。

进一步说,该常量用于另一个类的构造函数初始化器列表,并创建该另一个类的全局实例。

// mytype1.hpp
class MyType1
{
public:
    static const int g_myConstant = 42; // no definition in cpp
};

// mytype2.hpp
class MyType2
{
public:
    MyType2();
private:
    int m_myMember;
};

// mytype2.cpp
MyType2::MyType2()
    : m_myMember(MyType1::g_myConstant)
{
}

// otherfile.cpp
// is the reference to MyType1::g_myConstant in the ctor well defined?
MyType2 myType2GlobalInstance;

myType2GlobalInstance的结构定义是否正确?换句话说:C ++对static const类成员变量的静态初始化顺序有何保证?

由于没有定义该常量,因此可能没有需要初始化的内存,并且该变量的行为更像是预处理器宏。但这是否可以保证?是否定义常数会有所不同吗?

如果成员变量为static constexpr,它会发生任何变化吗?

1 个答案:

答案 0 :(得分:1)

对于静态初始化,直到C ++ 14,零初始化发生在常量初始化之前。从C ++ 14开始,将进行常量初始化而不是零初始化。常量初始化基本上发生在通过常量表达式(或constexpr构造函数)进行值初始化的对象和引用上。详细信息here

允许编译器使用常量初始化来初始化其他静态对象,前提是可以保证该值与遵循初始化的标准顺序相同。在实践中,常量初始化是在编译时执行的操作和预先计算的对象表示将作为程序映像的一部分存储。如果编译器不这样做,它仍然必须保证此初始化在任何动态初始化之前进行。

m_myMember不是静态初始化的,因为它的类构造函数不是constexprg_myConstant被常量初始化。使用static constexpr会强制编译器在编译时初始化值,如果没有constexpr,编译器可能会在编译时初始化。您的结构定义明确。

cppreference看这个例子:

#include <iostream>
#include <array>

struct S {
    static const int c;
};
const int d = 10 * S::c; // not a constant expression: S::c has no preceding
                         // initializer, this initialization happens after const
const int S::c = 5;      // constant initialization, guaranteed to happen first
int main()
{
    std::cout << "d = " << d << '\n';
    std::array<int, S::c> a1; // OK: S::c is a constant expression
//  std::array<int, d> a2;    // error: d is not a constant expression
}

但是现在,如果我们更改初始化顺序,它将编译:

#include <iostream>
#include <array>

struct S {
    static const int c;
};
//both inits are now constant initialization
const int S::c = 5;
const int d = 10 * S::c;
int main()
{
    std::cout << "d = " << d << '\n';
    std::array<int, S::c> a1;
    std::array<int, d> a2; //now, it's ok
}