C++ static const 和初始化(是否存在惨败)

发布于 2024-08-24 06:22:12 字数 1549 浏览 6 评论 0原文

时隔很长一段时间,我又回到了 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 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

转瞬即逝 2024-08-31 06:22:12

除了可能性 3 之外,所有这些都遭受静态初始化顺序失败的困扰。这是因为您的班级不是 POD。在C++0x中,可以通过标记构造函数constexpr来解决这个问题,但在C++03中没有这样的解决方案。

您可以删除构造函数来解决C++03中的问题,并使用初始化

const Vector2 Vector2::ONE = { 1.f, 1.f };

这是初始化一个POD,并且列表中的所有初始化器都是常量表达式(用于静态初始化的目的)。它们的初始化发生在任何可能在初始化之前访问它们的代码运行之前。

3.6.2:

具有静态存储持续时间(3.7.1)的对象应在任何其他初始化发生之前进行零初始化(8.5)。零初始化和用常量表达式初始化统称为静态初始化;所有其他初始化都是动态初始化。具有用常量表达式(5.19)初始化的静态存储持续时间的 POD 类型(3.9)的对象应在任何动态初始化发生之前进行初始化。

8.5.1/14:

当使用大括号括起来的初始化器列表初始化具有静态存储持续时间的聚合时,如果所有成员初始值设定项表达式都是常量表达式,并且聚合是 POD 类型,则初始化应在初始化的静态阶段完成(3.6.2);否则,不确定常量表达式成员的初始化是在初始化的静态阶段还是动态阶段进行。

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 constructor constexpr, but in C++03 there is no such solution.

You can remove the constructor to solve the problem in C++03, and initialize using

const Vector2 Vector2::ONE = { 1.f, 1.f };

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:

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.

梦晓ヶ微光ヅ倾城 2024-08-31 06:22:12

请注意,可能性 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

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文