内联初始化静态常量 class 成员的初始化顺序保证
Initialization order guarantees for inline-initialized static const class member
假设我有一个 static const int
class 成员变量。它直接在 class 定义中初始化,但它在 .cpp
中没有定义(这没关系,因为它不是 odr-used)。
此外,假设此常量在另一个 class 的构造函数初始化列表中使用,并且为另一个 class.
创建了一个全局实例
// 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
class成员变量的静态初始化顺序做了什么保证?
由于没有该常量的定义,因此可能没有需要初始化的内存,并且该变量的行为更像是预处理器宏..但这有保证吗?常量定义与否有区别吗?
如果成员变量是static constexpr
,它会改变什么吗?
对于静态初始化,直到 C++14,零初始化发生在常量初始化之前。从 C++14 开始,常量初始化发生而不是零初始化。常量初始化基本上发生在由常量表达式(或 constexpr 构造函数)值初始化的对象和引用中。详情 here.
允许编译器使用常量初始化来初始化其他静态对象,前提是它可以保证值与遵循标准初始化顺序相同。 在实际上,常量初始化在编译时执行,并且预先计算的对象表示作为程序映像的一部分存储。如果编译器不这样做,它仍然必须保证此初始化发生在任何动态初始化之前。
m_myMember
不是静态初始化的,因为它的class构造函数不是constexpr
。 g_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
}
假设我有一个 static const int
class 成员变量。它直接在 class 定义中初始化,但它在 .cpp
中没有定义(这没关系,因为它不是 odr-used)。
此外,假设此常量在另一个 class 的构造函数初始化列表中使用,并且为另一个 class.
创建了一个全局实例// 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
class成员变量的静态初始化顺序做了什么保证?
由于没有该常量的定义,因此可能没有需要初始化的内存,并且该变量的行为更像是预处理器宏..但这有保证吗?常量定义与否有区别吗?
如果成员变量是static constexpr
,它会改变什么吗?
对于静态初始化,直到 C++14,零初始化发生在常量初始化之前。从 C++14 开始,常量初始化发生而不是零初始化。常量初始化基本上发生在由常量表达式(或 constexpr 构造函数)值初始化的对象和引用中。详情 here.
允许编译器使用常量初始化来初始化其他静态对象,前提是它可以保证值与遵循标准初始化顺序相同。 在实际上,常量初始化在编译时执行,并且预先计算的对象表示作为程序映像的一部分存储。如果编译器不这样做,它仍然必须保证此初始化发生在任何动态初始化之前。
m_myMember
不是静态初始化的,因为它的class构造函数不是constexpr
。 g_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
}