第7.5章: constinit

English

概述

constinit 保证变量在编译期初始化,但与 constexpr 不同,变量本身不必是常量表达式。它只是确保初始化 发生在任何动态初始化之前。

这对避免静态初始化顺序问题极其有用。

1. 基础示例

constinit 变量必须用常量初始化器初始化,但变量本身 不必是 constexpr。


#include 

constinit int counter = 0;   // guaranteed compile-time initialization

int main()
{
    using namespace ::fast_io::iomnp;

    ++counter;                // OK: not constexpr
    print("counter = ", counter, "\n");
}

初始化在编译期完成,但变量在运行时是可变的。

2. 为什么这很有用

constinit 解决了一个真实问题:静态初始化顺序灾难。 它确保全局变量在任何动态初始化开始之前就已完成初始化。

没有 constinit 时,不同翻译单元中的两个全局变量 可能以不可预测的顺序初始化。

3. 避免静态初始化顺序问题

考虑位于不同文件中的两个全局变量:


// file A
#include 

constinit int global_value = 42;

// file B
extern int global_value;

int compute()
{
    return global_value * 2;   // safe: global_value is initialized early
}

由于 global_value 是 constinit 的,因此保证它在 compute() 运行之前就已完成初始化。

4. 与 constexpr 的区别

constexpr 意味着:

constinit 意味着:


constexpr int a = 5;     // constant expression, immutable
constinit int b = 5;     // compile-time init, mutable

b 可以在运行时改变;a 不能。

5. constinit 不强制常量求值

constinit 只要求初始化器是常量初始化器。它并不 强制该变量必须在常量表达式中使用。


constinit int x = 10;   // must be initialized at compile time
int y = x + 5;          // runtime use is fine

这使 constinit 非常适合那些必须尽早初始化、但仍然可变的 全局状态。

要点