跟我学C++中级篇——constinit避免SIOF

一、初始化的顺序

Static Initialization Order Fiasco, SIOF。静态初始化顺序问题。这里需要说明的是,静态初始化既包括静态变量也包括全局变量,因为它们都具有静态存储期。在前面文章中分析过,不同的库如果对全局变量有依赖的话,在某些情况下有可能会因初始化的依赖顺序导致意外的结果甚至崩溃。这也就是静态初始化问题的一个具体的表现。

SIOF问题产生的主要原因在于跨单元编译时,互相依赖的静态或全局变量,编译器无法保证其初始化的顺序,这是C++标准本身的原因,所以这个问题一直存在。

比如下面的代码:

c 复制代码
// a.cpp
extern int getData();
int g_A = getData(); // 依赖 b.ccp文件中g_B

// b.cpp
int g_B = 100;
int getData() { return g_B; }

在上述的代码中,如果初始化顺序不正确的话,就会让g_A产生不可控的值。

二、初始化的方式

具有静态存储期的变量在初始化的过程中,主要分为两个阶段:

  1. 静态初始化
    它主要包括零初始化(总提到的全局变量默认为0)和常量初始化。它在编译期完成即保证在程序运行前完成,从而保证了依赖顺序的安全性
  2. 动态初始化
    某些全局变量可能需要构造函数或函数调用的返回值来赋值,这就需要程序运行时才能解决。这时就会产生动态初始化,有可能导致SIOF。

三、constinit避免初始化依赖的原理

constinit要求必须使用常量表达式进行初始化并且在编译完成。constinit的引入,就是让全局变量在编译期的静态初始化这个阶段完成,去除静态初始化顺序中依赖的不确定性。但需要注意的是,其不能完全避免SIOF,除非依赖中的所有变量全部用由constinit限制实现。

四、限制场景

constinit虽然看上去可以解决SIOF,但它也有局限性。对于依赖运行时的值进行动态初始化的相关值时,其无法避免SIOF。同样,如果对于非字面类型,特别是构造函数非constexpr情况的,其同样也无法避免SIOF。

五、总结

如果说灵活是C++的特点,constinit则体现了C++的另外一面。它就是刻板的要求修饰的变量必须在编译期初始化完成。这种刻板恰恰与灵活相辅相成,正如事物的两面性,刻板保证了灵活的安全,灵活动态的使用了刻板。互相成就,千变万化。

相关推荐
汉克老师14 小时前
GESP2025年3月认证C++五级( 第三部分编程题(1、平均分配))
c++·算法·贪心算法·排序·gesp5级·gesp五级
智者知已应修善业17 小时前
【51单片机2个按键控制流水灯运行与暂停】2023-9-6
c++·经验分享·笔记·算法·51单片机
云泽80818 小时前
C++11 核心特性全解:列表初始化、右值引用与移动语义实战
开发语言·c++
AI进化营-智能译站19 小时前
ROS2 C++开发系列12-用多态与虚函数构建可扩展的ROS2机器人行为模块
开发语言·c++·ai·机器人
Morwit19 小时前
QML组件之间的通信方案(暴露子组件)
c++·qt·职场和发展
qeen8719 小时前
【数据结构】建堆的时间复杂度讨论与TOP-K问题
c语言·数据结构·c++·学习·
图码20 小时前
如何用多种方法判断字符串是否为回文?
开发语言·数据结构·c++·算法·阿里云·线性回归·数字雕刻
handler0120 小时前
Linux 内核剖析:进程优先级、上下文切换与 O(1) 调度算法
linux·运维·c语言·开发语言·c++·笔记·算法
zhouwy11320 小时前
Linux进程与线程编程详解
linux·c++
A7bert77721 小时前
【YOLOv8pose部署至RDK X5】模型训练→转换bin→Sunrise 5部署
c++·python·深度学习·yolo·目标检测