C++ static const 和初始化(是否存在惨败)
时隔很长一段时间,我又回到了 C++,对众所周知的静态初始化问题的理解有些磕磕绊绊。
假设我有一个简单的类 Vector2,如下所示(请注意,我知道 x 和 y 对于 getter 和 setter 应该是私有的,为了简洁起见,这些都被省略了):
class Vector2 {
public:
Vector2(float x, float y) :x(x), y(y) {};
float x,y;
}
现在,如果我想指定一个 static const 成员表示 x 和 y 设置为 1 的 Vector2,我不确定如何继续 - static const 成员是否会遇到静态初始化问题,或者使它们成为 const 的行为是否意味着它们没问题?我正在考虑以下可能性:
可能性 1:
// .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;
}
可能性 3:
// .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;
}
现在,我更喜欢的编写方式是可能性 2,因为它对我来说是一种更舒适的语法。但是,如果我从另一个类中的另一个静态方法调用 getOne() 方法,我是否会面临崩溃和烧毁的风险?正如我所说,正是因为我使用的是 static const 而不是普通的 static,所以我才问这个问题,因为我在普通的静态类成员问题上发现了很多,但在 const static 问题上却没有发现任何内容。
我怀疑我使用 static const 并没有得到任何好处,并且需要使用可能性 3 才能安全,但我只是想问是否有人可以为我阐明这一点。
我意识到我可能正在向大量链接开放,这些链接正是指向我要问的内容,但在发布此内容之前我已经查看过但没有找到。
任何帮助将不胜感激。
I am returning to C++ after a long absence and I am stumbling a little over my understanding of the fairly well known static initialization problem.
Let's say I have a simple class Vector2 as given below (note that I am aware that x and y should be private with getters and setters, these have just been omitted for brevity):
class Vector2 {
public:
Vector2(float x, float y) :x(x), y(y) {};
float x,y;
}
Now, if I want to specify a static const member to represent a Vector2 with x and y set to 1, I am unsure on how to proceed - will static const members fall foul of the static initialization problem or will the act of making them const mean they are ok? I am toying with the following possibilities:
Possibility 1:
// .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);
Possibility 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;
}
Possibility 3:
// .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;
}
Now, my preferred way to write this would be as in possibility 2, just because it is a more comfortable syntax for me. However, if I call the getOne() method from another static method in another class am I going to risk crashing and burning? As I say, it is because I am using a static const rather than a plain static that I am asking this question as I have found much on plain static class member issues, but nothing on const static issues.
I suspect that I gain nothing by the fact that I am using static const and will need to go with Possibility 3 to be safe, but I just want to ask in case someone can shed some light on this for me.
I realise I am probably opening myself up to a slew of links pointing to exactly what I am asking, but I have looked and not found before posting this.
Any help will be gratefully appreciated.
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(2)
除了可能性
3
之外,所有这些都遭受静态初始化顺序失败的困扰。这是因为您的班级不是 POD。在C++0x中,可以通过标记构造函数constexpr
来解决这个问题,但在C++03中没有这样的解决方案。您可以删除构造函数来解决C++03中的问题,并使用初始化
这是初始化一个POD,并且列表中的所有初始化器都是常量表达式(用于静态初始化的目的)。它们的初始化发生在任何可能在初始化之前访问它们的代码运行之前。
3.6.2:
8.5.1/14:
All of them, except possibility
3
, suffer from the static initialization order fiasco. This is because your class is not a POD. In C++0x, this problem can be solved by marking the constructorconstexpr
, but in C++03 there is no such solution.You can remove the constructor to solve the problem in C++03, and initialize using
This is initializing a POD, and all initializers in the list are constant expression (for the purpose of static initialization). The intialization of them happen before any code is run that might access it before being initialized.
3.6.2
:8.5.1/14
:请注意,可能性 3 不是线程安全的。
例如,请参阅“C++ 作用域静态初始化不是线程安全的,是故意的!”在 http://blogs.msdn.com/b/ oldnewthing/archive/2004/03/08/85901.aspx
Please note that possibility 3 is not thread safe.
See for example "C++ scoped static initialization is not thread-safe, on purpose!" at http://blogs.msdn.com/b/oldnewthing/archive/2004/03/08/85901.aspx