饿汉式单例启动即初始化,天然线程安全;懒汉式首次调用才创建,需用std::call_once或双重检查锁定保障线程安全,但易出错,推荐优先使用饿汉式。
饿汉式在程序加载时就完成实例构造,后续所有调用都直接返回已创建的对象指针,不存在多线程竞争问题,无需加锁。
关键点在于 static 成员变量的初始化时机由编译器保证——C++11 起,static 局部变量的初始化是线程安全的;而静态成员变量(如类内定义的 static Instance*)在 main() 执行前完成,且仅一次。
常见错误是把指针声明和 new 拆开写,导致非原子操作:
class Singleton {
private:
static Singleton* instance;
Singleton() = default; // 防止外部构造
public:
static Singleton* getInstance() {
return instance; // ❌ instance 可能为 nullptr 或未初始化
}
};
Singleton* Singleton::instance = new Singleton(); // ✅ 此行才真正构造更推荐写法(C++11+):
立即学习“C++免费学习笔记(深入)”;
class Singleton {
private:
Singleton() = default;
Singleton(const Singleton&) = delete;
Singleton& operator=(const Singleton&) = delete;
public:
static Singleton& getInstance() {
static Singleton in
stance; // ✅ 局部静态变量,线程安全初始化
return instance;
}
};main 结束后按逆序销毁,若其他静态对象依赖它,可能访问已析构对象懒汉式延迟资源占用,但 getInstance() 中的判空 + 构造逻辑不是原子操作,多线程下极易出现重复 new 或返回未完全构造的对象。
典型错误写法(双重检查锁定漏锁):
static Singleton* getInstance() {
if (instance == nullptr) { // 第一次检查
instance = new Singleton(); // ❌ 构造+赋值非原子,可能被重排,其他线程看到半初始化对象
}
return instance;
}正确实现(C++11 double-checked locking pattern):
class Singleton {
private:
static std::atomic instance;
static std::mutex mtx;
Singleton() = default;
public:
static Singleton* getInstance() {
Singleton* tmp = instance.load(std::memory_order_acquire);
if (tmp == nullptr) {
std::lock_guard lock(mtx);
tmp = instance.load(std::memory_order_relaxed);
if (tmp == nullptr) {
tmp = new Singleton();
instance.store(tmp, std::memory_order_release);
}
}
return tmp;
}
};
std::atomic Singleton::instance{nullptr};
std::mutex Singleton::mtx; std::atomic 替代裸指针,否则无法防止指令重排memory_order_acquire 和 memory_order_release 保证构造完成后再对其他线程可见std::call_once
相比手写 DCLP,std::call_once 更简洁、不易出错,且由标准库保证绝对只执行一次。
class Singleton {
private:
static Singleton* instance;
static std::once_flag init_flag;
Singleton() = default;
public:
static Singleton* getInstance() {
std::call_once(init_flag, []() {
instance = new Singleton();
});
return instance;
}
};
Singleton* Singleton::instance = nullptr;
std::once_flag Singleton::init_flag;std::call_once 内部已做线程同步,无需额外锁或原子操作instance 仍需声明为 static,且不能在 lambda 外提前使用std::unique_ptr 包裹并注册 atexit),否则内存泄漏饿汉式看似“浪费”,实则规避了绝大多数线程安全陷阱;懒汉式看似灵活,却把复杂性推给了开发者。
真实项目中容易被忽略的点:
std::call_once,其内部实现依赖 OS 级同步原语,在极低概率下(如 fork 后)可能异常,但绝大多数场景可忽略constinit,但目前对单例帮助有限,仍无法解决跨编译单元初始化顺序问题除非明确知道构造开销极大、且确定不会引发静态初始化依赖,否则默认用饿汉式(局部静态变量版本)最省心。
# ai
# c++
# 延迟加载
# 标准库
# Static
# 成员变量
# 构造函数
# 局部变量
# double
# Lambda
# 指针
# 线程
# 多线程
# 对象
# 首次
# 加锁
# 仍需
# 加载
# 多个
# 已被
# 两次
# 能在
# 给了
相关栏目:
【
Google疑问12 】
【
Facebook疑问10 】
【
网络优化76771 】
【
技术知识130152 】
【
IDC云计算60162 】
【
营销推广131313 】
【
AI优化88182 】
【
百度推广37138 】
【
网站推荐60173 】
【
精选阅读31334 】
相关推荐:
Win10电脑怎么设置IP地址_Windows10网络属性固定IP配置
TestNG的testng.xml配置文件怎么写
如何用正则表达式精确匹配最多含一个换行符的起止片段
Win11关机快捷键是什么_Win11快速关机方法【大全】
如何外贸网站设计-能留住客户提升用户体验!
Windows10无法连接到Internet_Win10网络重置命令详解
Windows10怎么查看系统激活状态_Windows10激活状态查看方法【教程】
php中常量能用::访问吗_类常量与作用域操作符使用场景【汇总】
Win11怎么设置触控板手势_Windows11三指四指操作自定义
C#如何序列化对象为XML XmlSerializer用法
Python与GPU加速技术_CUDA与Numba高性能计算实践
Windows11如何设置专注助手_Windows11专注助手使用攻略【技巧】
Mac的“调度中心”与“空间”怎么用_Mac多桌面高效管理【技巧】
Python类装饰器使用_元编程解析【教程】
Win11怎么关闭键盘按键音_Win11禁用打字声音反馈【教程】
XSLT怎么生成动态的HTML属性名和标签名
如何使用Golang实现容器自动化运维_Golang Docker运维管理方法
php嵌入式需要什么环境_搭建php+linux嵌入式开发环境【详解】
Win10怎样设置闹钟贪睡时间 Win10闹钟贪睡时长设置【步骤】
Win10怎样设置多显示器_Win10多显示器扩展设置【攻略】
PHP主流架构怎么部署到Docker_容器化流程【操作】
如何在Windows上设置闹钟和计时器_系统自带的时钟应用全攻略【生活技巧】
Windows家庭版如何开启组策略(gpedit.msc)?(安装方法)
c++如何使用std::bitset进行位图算法_c++ 快速查找与大规模数据排重【方法】
Win11怎么开启远程桌面连接_Windows11系统属性远程设置
Python多进程教程_multiprocessing模块实战
Windows服务无法启动错误1067是什么_进程意外终止的解决方法
php订单日志怎么记录物流_php记录订单物流变更日志指南【指南】
如何使用Golang捕获测试日志_Golang testing日志记录方法
短链接怎么用php还原_从基础原理到代码实现教学【详解】
c++如何利用doxygen生成开发文档_c++ 代码注释规范与HTML文档导出【案例】
Windows10如何更改计算机工作组_Win10系统属性修改Workgroup
如何在 Go 中正确反序列化多个并列的 XML 元素(而非 XML 数组)
Mac电脑进水了怎么办_MacBook进水后紧急处理方法【必看】
使用类变量定义字符串常量时的类型安全最佳实践
Win11如何设置自动关机 Win11定时关机命令使用教程【技巧】
php做exe支持多线程吗_并发处理实现方式【详解】
php485返回数据不完整怎么办_php485数据分包重组处理方法【教程】
Python抽象类与接口设计_规范说明【指导】
Win11怎么设置虚拟键盘_打开Win11屏幕键盘操作指南【技巧】
如何在Golang中实现邮件发送功能_Golang SMTP发送与错误处理示例
英国搜索:多数英国人认为语言搜索是未来搜索
Windows10电脑怎么设置文件权限_Win10安全选项卡所有者修改
Windows10系统怎么查看IP地址_Win10网络连接状态详细信息
Python如何创建带属性的XML节点
如何使用正则表达式提取以编号开头、后跟多个注解的完整代码块
Win10怎样卸载iTunes_Win10卸载iTunes步骤【步骤】
Python 中将 ISO 8601 时间戳转换为日期并计算日期差值的完整教程
Windows 10怎么录屏_Windows 10使用Xbox Game Bar录制屏幕视频教程
Python大文件处理策略_内存优化说明【指导】
2026-01-03
致胜网络推广营销网专注海外推广十年,是谷歌推广.Facebook广告全球合作伙伴,我们精英化的技术团队为企业提供谷歌海外推广+外贸网站建设+网站维护运营+Google SEO优化+社交营销为您提供一站式海外营销服务。