Что такое "constinit" в С++ 20?

constinit - это новый ключевое слово и спецификатор в С++ 20, который был предложен в P1143.

Следующий пример приведен в стандарте:

const char * g() { return "dynamic initialization"; }
constexpr const char * f(bool p) { return p ? "constant initializer" : g(); }
constinit const char * c = f(true);     // OK
constinit const char * d = f(false);    // ill-formed

На ум приходит несколько вопросов:

  • Что означает constinit? Почему это было введено? В каких случаях мы должны его использовать?

  • Делает ли это переменную неизменной? Это подразумевает const или constexpr?

  • Может ли переменная быть const и constinit? Как насчет constexpr и constinit?

  • К каким переменным можно применить спецификатор? Почему мы не можем применить его к переменным non- static, non- thread_local?

  • Есть ли у нее какие-либо преимущества в производительности?

Этот вопрос предназначен для использования в качестве справочного материала для предстоящих вопросов о constinit в целом.

Ответы

Ответ 1

  •    Что означает constinit? Почему это было введено? В каких случаях мы должны его использовать?

Инициализация переменной с статической продолжительностью хранения может привести к двум результатам¹:

  1. Переменная инициализируется во время компиляции (constant-initialization);

  2. Переменная инициализируется при первом прохождении контроля через ее объявление.

Случай (2) проблематичен, поскольку может привести к статическому порядку инициализации fiasco, который является источником опасных ошибок, связанных с глобальными объектами.

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

Использование constinit гарантирует, что переменная инициализируется во время компиляции, и что фиаско статического порядка инициализации не может иметь место.


  • Делает ли это переменную неизменной? Это подразумевает const или constexpr?

Нет и нет.

Однако constexpr подразумевает constinit.


  • Может ли переменная быть const и constinit? Как насчет constexpr и constinit?

Это может быть как const, так и constinit. Это не может быть constexpr и constinit. Из формулировки:

  Не более одного из ключевых слов constexpr, consteval и constinit должно появляться в decl-specier-seq.


  • К каким переменным можно применить спецификатор? Почему мы не можем применить его к переменным non- static, non- thread_local?

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


  • Есть ли у нее какие-либо преимущества в производительности?

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


See: см https://en.cppreference.com/w/cpp/language/storage_duration#Static_local_variables