警告 C26426

全局初始值设定项调用非 constexpr 函数“symbol”(i.22)

C++ Core Guidelines

I.22:避免对全局对象进行复杂的初始化

全局对象的初始化程序的执行顺序可能不一致或未定义,这可能导致难以重现和调查的问题。 为了避免此类问题,全局初始化程序不应依赖于运行时执行的可能依赖于尚未初始化的数据的外部代码。 此规则会标记全局对象调用函数来获取其初始值的情况。

备注

  • 该规则忽略对 constexpr 函数或内部函数的调用,其假定要么在编译时计算这些调用,要么在运行时保证可预测的执行。

  • 它仍会标记对内联函数的调用,因为检查器不会尝试分析其实现。

  • 在许多常见方案(全局初始化用户定义类型的变量(或标准容器))中,此规则可能会带来干扰。 这通常是由于调用构造函数和析构函数所致。 它仍然是一个有效的警告,因为它指向可能存在不可预测行为或外部代码未来更改可能导致不稳定性的位置。

  • 静态类成员被视为全局成员,因此也会检查其初始值设定项。

代码分析名称:NO_GLOBAL_INIT_CALLS

示例

外部版本检查:

// api.cpp
int api_version = API_DEFAULT_VERSION; // Assume it can change at run time, hence non-const.
int get_api_version() noexcept {
    return api_version;
}

// client.cpp
int get_api_version() noexcept;
bool is_legacy_mode = get_api_version() <= API_LEGACY_VERSION; // C26426, also stale value

外部版本检查提高了可靠性:

// api.cpp
int& api_version() noexcept {
    static auto value = API_DEFAULT_VERSION;
    return value;
}
int get_api_version() noexcept {
    return api_version();
}

// client.cpp
int get_api_version() noexcept;
bool is_legacy_mode() noexcept {
    return get_api_version() <= API_LEGACY_VERSION;
}