недавний вопрос обратил мое внимание на то, как constexpr
изменилось в C ++ 14. Новая функция заключается в том, что нелокальная переменная со статической продолжительностью хранения может быть инициализирована на этапе статической инициализации, если ее инициализатор состоит из constexpr
конструктор, даже если тип переменной не является литеральным типом. Точнее, новая формулировка в [basic.start.init]:
постоянный инициализатор для объекта
o
является выражением, которое является константным выражением, за исключением того, что оно может также вызывать конструкторы constexpr дляo
и его подобъекты, даже если эти объекты не литеральных типов классов [Заметка: такой класс может иметь нетривиальный деструктор — конечная нота]. Постоянная инициализация выполняется […], если объект со статическим или потоковым хранилищем инициализируется вызовом конструктора, и если полное выражение инициализации является постоянным инициализатором для объекта […]
Типичный пример std::unique_ptr
который «никогда не должен быть хуже рукописного»:
std::unique_ptr<int> p; // statically initialized by [unique.ptr.single.ctor],
// requires no code excution
int main()
{
p = std::make_unique<int>(100);
}
// p is destroyed eventually
До этого дополнения статически инициализированные переменные имели либо ссылочный тип, либо буквальный тип объекта и, следовательно, имели тривиальные деструкторы. Но теперь статически инициализированная глобальная переменная может иметь нетривиальный деструктор.
Как упорядочивается такой вызов деструктора по отношению к деструкторам динамически инициализированных глобальных объектов по сравнению с другими статически инициализированными и как секвенируются вызовы деструктора?
Рассматривать
Если объект инициализируется статически, объект уничтожается в
тот же порядок, как если бы объект был динамически инициализирован.
а также
Если завершение конструктора или динамическая инициализация
Объект со статической продолжительностью хранения упорядочен до
другой, завершение деструктора второго секвенируется
до посвящения деструктора в первый.
Сейчас,
Статическая инициализация должна быть выполнена перед любой динамической
инициализация происходит.
Очевидно, это отвечает на первый вопрос: p
гарантированно инициализируется перед выполнением любой динамической инициализации, вызывается деструктор после любой динамически инициализированный объект уничтожается.
По сути, второй вопрос, т. Е. В каком порядке происходит разрушение нескольких статически инициализированных переменных, сводится к порядку инициализации этих:
Динамическая инициализация нелокальной переменной со статическим хранилищем
продолжительность либо упорядочена, либо неупорядочена. Определения явно
члены статических данных шаблона специализированного класса заказали
инициализация. Другие члены статических данных шаблона класса (т.е.
неявно или явно созданные специализации) имеют неупорядоченные
инициализация. Другие нелокальные переменные со статическим хранилищем
длительность заказали инициализацию.
Жирное предложение включает в себя все статически инициализированные объекты, которые не являются статическими членами данных экземпляров классов. Они заказаны в пределах одной единицы перевода:
Переменные с упорядоченной инициализацией, определенной в одном
Блок перевода инициализируется в порядке их
определения в переводческой единице.
Итак, подведем итог:
Переменные, которые являются объектом статической инициализации и не являются статическими членами данных экземпляра класса, уничтожаются в обратном порядке определения в файле перевода.
… эти переменные всегда уничтожаются после уничтожения любого динамически инициализированного объекта.
Однако, несмотря на возможные аргументативные ошибки, ни Clang, ни GCC, похоже, не реализуют это сейчас: демонстрация.
[basic.start.term]/1
(N4140) говорит:
Если объект инициализируется статически, объект уничтожается в том же порядке, как если бы объект был динамически инициализирован.
Как я понимаю, это означает, что с целью определения порядка разрушения вся статическая инициализация рассматривается как динамическая (упорядоченная или неупорядоченная), и деструкторы вызываются в обратном порядке этой инициализации.