A недавний вопрос привлек мое внимание к тому, как constexpr
изменился на С++ 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
До этого добавления статически инициализированные переменные были либо ссылочного типа, либо типа литерала, и поэтому имели тривиальные деструкторы. Но теперь статически инициализированная глобальная переменная может иметь нетривиальный деструктор.
Как устроен такой деструкторный вызов по отношению к деструкторам динамически инициализированных глобальных объектов по отношению к другим статически инициализированным и как упорядочиваются вызовы деструктора?