C ++ статическая константа и инициализация (фиаско) - PullRequest
6 голосов
/ 03 марта 2010

Я возвращаюсь в C ++ после долгого отсутствия и немного спотыкаюсь о своем понимании довольно известной проблемы статической инициализации.

Допустим, у меня есть простой класс Vector2, как указано ниже (обратите внимание, что я знаю, что x и y должны быть частными с геттерами и сеттерами, они просто опущены для краткости):

class Vector2 {

public:
  Vector2(float x, float y) :x(x), y(y) {};
  float x,y;
}

Теперь, если я хочу указать статический член const для представления Vector2 с x и y, установленным в 1, я не уверен в том, как поступить - будут ли статические члены 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 () из другого статического метода в другом классе, могу ли я рискнуть потерпеть крах и записать? Как я уже сказал, именно потому, что я использую статический констант, а не простую статическую, я задаю этот вопрос, так как я нашел много вопросов о простых статических членах класса, но ничего о константных статических проблемах.

Я подозреваю, что ничего не выиграю из-за того, что я использую статический констант, и мне нужно перейти с возможностью 3, чтобы быть в безопасности, но я просто хочу спросить, может ли кто-нибудь пролить свет на это для меня.

Я понимаю, что, вероятно, открываю себя множеству ссылок, указывающих именно на то, что я прошу, но я посмотрел и не нашел, прежде чем опубликовать это.

Буду признателен за любую помощь.

Ответы [ 2 ]

10 голосов
/ 03 марта 2010

Все они, кроме возможности 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) перед любой другой инициализацией. Обнуление инициализации и инициализация с постоянным выражением вместе называются статической инициализацией; все остальные инициализации - это динамическая инициализация. Объекты типов POD (3.9) со статической продолжительностью хранения, инициализированные с помощью константных выражений (5.19), должны быть инициализированы перед любой динамической инициализацией.

8.5.1/14

Когда агрегат со статической продолжительностью хранения инициализируется с помощью заключенного в скобки списка инициализаторов, если все выражения инициализатора члена являются константными выражениями, а агрегат является типом POD, инициализация должна выполняться во время статической фазы инициализации (3.6.2); в противном случае не определено, происходит ли инициализация элементов с постоянными выражениями во время статической фазы или во время динамической фазы инициализации.

1 голос
/ 04 ноября 2011

Обратите внимание, что возможность 3 не является поточно-ориентированной.

См., Например, "Статическая инициализация в области C ++ специально не ориентирована на многопотоковое исполнение!" на http://blogs.msdn.com/b/oldnewthing/archive/2004/03/08/85901.aspx

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...