You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

内联变量的初始化销毁顺序、实例化规则及相关问题问询

C++内联变量常见问题解答

问题背景

用户给出了依赖内联变量的代码示例,发现未被引用的内联变量也会被实例化,并提出四个相关问题。

全局内联变量示例

#include <memory>
#include <iostream>

struct A
{
    A() : p(std::make_shared<int>(5)) {}

    std::shared_ptr<int> p;
};

struct B
{
    B(A& a) : p(a.p.get()) { func(); }

    ~B() { func(); }

    void func() { std::cout << *p; }

    int* p;
};

inline A a;
inline B b(a);

int main()
{
    return 0;
}

类内静态内联变量示例

class C
{
public:

    static inline A a;
    static inline B b = B(a);
};

问题解答

1. 是否能保证b在a之后创建、在a之前销毁?

可以保证,分两种场景:

  • 同一翻译单元的全局inline变量:C++标准规定,同一翻译单元内的全局对象初始化顺序遵循声明顺序,销毁顺序则与初始化顺序相反。因此a会先于b构造,b会先于a销毁,完全匹配依赖关系。
  • 类内静态inline变量:同一类中的静态inline变量,初始化顺序严格遵循类内的声明顺序,销毁顺序同样反向。因此C::a先构造,C::b后构造;销毁时C::b先执行析构,C::a后执行。

2. 内联变量是否即使未被引用也总会被实例化?

通常情况下是的。C++标准要求inline变量的定义必须存在于每个用到它的翻译单元中,且编译器需确保其唯一实例化。即使代码中没有显式引用该变量,编译器一般也会完成初始化(正如你示例中输出55的情况)。不过极端优化场景下,编译器可能会移除未被使用的inline变量,但这种情况非常少见,且不符合常规编译行为。

3. 第一个代码示例中移除inline会有哪些变化?

移除inline后,a和b变为普通全局变量,主要变化有三点:

  • 链接属性:普通全局变量是外部链接,若此代码被多个翻译单元包含,会触发多重定义错误(违反ODR规则);而inline变量允许在多个翻译单元中定义,最终合并为单一实体。
  • 实例化行为:普通全局变量若未被ODR使用(即代码中没有直接引用它),编译器大概率会优化掉其初始化操作,你的代码将不会输出55。
  • 跨TU风险:如果仅在单个翻译单元中使用,初始化顺序仍遵循声明顺序,但一旦跨翻译单元使用,会引入未定义行为风险。

4. 若a和b处于不同翻译单元会发生什么?

分两种情况讨论:

  • 均为inline变量:不同翻译单元中的inline变量会被视为同一实体,但跨翻译单元的全局对象初始化顺序是未指定的。这意味着b可能在a完成初始化前就被构造,导致b.p指向未初始化的a.p,触发运行时崩溃或未定义行为。
  • 均为非inline变量:首先会面临链接问题——若b所在TU未声明a为外部变量,会出现未定义符号错误;即使声明正确,跨TU的全局变量初始化顺序依然未指定,同样会导致b依赖的a未完成初始化,引发未定义行为。

内容的提问来源于stack exchange,提问作者Alexey Starinsky

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.18 20:35:24