Имеют ли объекты встроенных типов особый статический приоритет порядка инициализации? - PullRequest
6 голосов
/ 06 января 2012

Я ожидал, что следующий код приведет к ошибке сегментации (или иначе UB):

struct T {
   T();
};

T t;
char const* str = "Test string";

T::T() {
   std::cout << str; // zero-initialised, only!
}

int main() {}

Это потому, что t инициализируется раньше str. Я ожидаю, что str будет содержать значение (char const*)0 из-за инициализации нуля. Моя интерпретация [C++11: 3.6.2/2] подтверждает это.

Однако приведенный выше фрагмент выглядит для вывода строки, как ожидалось (и я подтвердил поведение, также напечатав значение указателя).

Есть ли какое-то правило статической инициализации, которое я здесь упускаю, которое позволяет str быть инициализированным значением до того, как t начнет конструирование? Где это в стандарте?


Это возникло при разрешении статической переменной во время сборки , когда ответчик утверждал, что использование char const* вместо std::string для статической глобализации позволяет избежать фиаско статического порядка инициализации. Я не согласен, но теперь я не уверен ...

Ответы [ 4 ]

6 голосов
/ 06 января 2012

str инициализируется константным выражением, а const char * является типом POD (термины C ++ 03, но в C ++ 11 это аналогично, но с другими терминами и более разрешенными падежами).Такая инициализация выполняется на этапе инициализации static , а на этапе инициализации static порядок не возникает.Это происходит перед любой динамической инициализацией.t инициализируется в фазе динамической инициализации.

1 голос
/ 06 января 2012

Я думаю, что нашел это;здесь происходит не столько встроенный тип, сколько постоянный инициализатор:

[C++11: 3.6.2/2]: Переменные со статической продолжительностью хранения (3.7.1) или продолжительностью хранения потоков (3.7.2) должен быть инициализирован нулем (8.5) перед любой другой инициализацией.

Инициализация константы выполняется:

  • , если каждая полное выражение (включая неявные преобразования), которое появляется в инициализаторе ссылки со статической или продолжительностью хранения потока, является константным выражением (5.19), и ссылка связана с lvalue, обозначающим объект со статической продолжительностью храненияили временному (см. 12.2);
  • , если объект со статической или продолжительностью хранения потока инициализируется вызовом конструктора, если конструктор является конструктором constexpr, если все аргументы конструктора являются константными выражениями (включаяпреобразования), и, если после подстановки вызова функции (7.1.5), каждый вызов конструктора и full-expвозврат в mem-инициализаторах и в фигурных скобках или равных инициализаторах для нестатических элементов данных является константным выражением;
  • , еслиобъект со статическим или потоком хранения не инициализируется вызовом конструктора, и если каждое полное выражение , которое появляется в его инициализаторе, является константным выражением.

Вместе нулевая инициализация и постоянная инициализация называются статической инициализацией;все остальные инициализации - это динамическая инициализация.Статическая инициализация должна быть выполнена до того, как произойдет какая-либо динамическая инициализация. [..]

Это последнее предложение, как представляется, переопределяет последующие правила упорядочения, что делает этот порядок применимым ко всем единицам перевода.

1 голос
/ 06 января 2012

Встроенные типы вообще не инициализируются, в обычном смысле. Обычно их начальное содержимое отображается в памяти непосредственно из специальной области двоичного файла как часть его загрузки.

0 голосов
/ 06 января 2012
char const* str = "Test string";

выполняется компилятором / компоновщиком, поэтому он существует в своем «инициализированном состоянии» еще до запуска программы.

...