我在久违后重返 C++,我对众所周知的静态初始化问题的理解有些磕磕绊绊。
假设我有一个简单的类 Vector2,如下所示(请注意,我知道 x 和 y 应该与 getter 和 setter 私有(private),为简洁起见,这些只是被省略了):
class Vector2 {
public:
Vector2(float x, float y) :x(x), y(y) {};
float x,y;
}
现在,如果我想指定一个静态常量成员来表示 x 和 y 设置为 1 的 Vector2,我不确定如何进行——静态常量成员是否会陷入静态初始化问题或让他们 const 意味着他们还好吗?我正在考虑以下可能性:
可能性一:
// .h
class Vector2 {
public:
Vector2(float x, float y) :x(x), y(y) {}
static const Vector2 ONE;
float x,y;
};
// .cpp
const Vector2 Vector2::ONE = Vector2(1.f, 1.f);
可能性2:
// .h
class Vector2 {
public:
Vector2(float x, float y) :x(x), y(y) {}
static const Vector2& getOne();
float x,y;
private:
static const Vector2 ONE;
};
// .cpp
const Vector2 Vector2::ONE = Vector2(1.f, 1.f);
static const Vector2& Vector2::getOne() {
return ONE;
}
可能性三:
// .h
class Vector2 {
public:
Vector2(float x, float y) :x(x), y(y) {}
static const Vector2& getOne();
float x,y;
};
// .cpp
const Vector2& Vector2::getOne() {
static Vector2 one(1.f,1.f);
return one;
}
现在,我更喜欢用第二种方式来编写它,因为它对我来说是一种更舒适的语法。但是,如果我从另一个类中的另一个静态方法调用 getOne() 方法,我是否会面临崩溃和燃烧的风险?正如我所说,这是因为我使用的是静态 const 而不是普通静态,所以我问这个问题,因为我在普通静态类成员问题上发现了很多,但在 const static 问题上却一无所获。
我怀疑我使用的是 static const 并且需要使用可能性 3 以确保安全,这一事实让我一无所获,但我只是想问一下,以防有人能为我阐明这一点。
我意识到我可能会打开大量指向我所问内容的链接,但在发布此之前我已经看过但没有找到。
如有任何帮助,我们将不胜感激。
最佳答案
除了可能性 3
之外,所有这些都遭受了静态初始化顺序的失败。这是因为您的类(class)不是 POD。在C++0x中,这个问题可以通过标记构造函数constexpr
来解决,但是在C++03中没有这样的解决方法。
在C++03中可以去掉构造函数解决问题,使用初始化
const Vector2 Vector2::ONE = { 1.f, 1.f };
这是在初始化一个POD,列表中的所有初始化器都是常量表达式(用于静态初始化)。它们的初始化发生在运行任何可能在初始化之前访问它的代码之前。
3.6.2
:
Objects with static storage duration (3.7.1) shall be zero-initialized (8.5) before any other initialization takes place. Zero-initialization and initialization with a constant expression are collectively called static initialization; all other initialization is dynamic initialization. Objects of POD types (3.9) with static storage duration initialized with constant expressions (5.19) shall be initialized before any dynamic initialization takes place.
8.5.1/14
:
When an aggregate with static storage duration is initialized with a brace-enclosed initializer-list, if all the member initializer expressions are constant expressions, and the aggregate is a POD type, the initialization shall be done during the static phase of initialization (3.6.2); otherwise, it is unspecified whether the initialization of members with constant expressions takes place during the static phase or during the dynamic phase of initialization.
关于C++ static const 和初始化(有没有惨败),我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/2373859/