Я возвращаюсь к C++ после долгого отсутствия, и я спотыкаюсь немногим более, чем свое понимание довольно хорошо известной статической проблемы инициализации.
Скажем, у меня есть простой класс Vector2, как дали ниже (обратите внимание, что я знаю, что X и Y должны быть частными с методами считывания и методами set, они были просто опущены для краткости):
class Vector2 {
public:
Vector2(float x, float y) :x(x), y(y) {};
float x,y;
}
Теперь, если я хочу указать статического участника константы для представления Vector2 с набором X и Y к 1, я не уверен о том, как продолжить двигаться - статические участники константы будут ссориться со статической проблемой инициализации, или будет действие создания их, константа означает, что они в порядке? Я играю со следующими возможностями:
Возможность 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 для сейфа, но я просто хочу спросить в случае, если кто-то может пролить некоторый свет на это для меня.
Я понимаю, что, вероятно, открываю меня до убивания ссылок, указывающих точно, что я спрашиваю, но я посмотрел и не нашел прежде, чем отправить это.
Любая справка будет с благодарностью цениться.
Все они, за исключением возможности 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); в противном случае не указано, происходит ли инициализация членов с константными выражениями во время статической фазы или во время динамической фазы инициализации.