饿汉式单例启动即初始化,天然线程安全;懒汉式首次调用才创建,需用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 】
相关推荐:
Python爬虫项目实战教程_Scrapy抓取与存储数据实例
Windows如何设置登录时的欢迎屏幕背景?(锁屏界面)
C++如何解析JSON数据?(nlohmann/json库示例)
Windows蓝屏错误0x00000023怎么修复_FAT文件系统错误处理
windows系统如何安装cab更新补丁_windows手动安装更新包教程
PhpStorm怎么调试PHP代码_PhpStorm断点设置与调试启动步骤【指南】
Win11怎么查看已连接wifi密码 Win11查已连wifi密码步骤【教程】
如何正确访问 Laravel 模型或对象的属性而非调用不存在的方法
如何在Golang中配置代码格式化工具_使用gofmt和goimports
如何测试您的网站全球打开速度-网站海外测速工
php在Linux怎么部署_LNMP环境搭建PHP服务的详细指南【指南】
c# F# 的 MailboxProcessor 和 C# 的 Actor 模型
如何优化Golang Web性能_Golang HTTP服务器性能提升方法
Windows10电脑怎么设置文件权限_Win10安全选项卡所有者修改
Win11怎么查看电脑配置_Win11硬件配置详细查询方法【详解】
Mac如何解压zip和rar文件?(推荐免费工具)
Win11怎么设置ip地址_Windows 11手动配置网络IP教程【详解】
如何使用Golang优化模块引入路径_Golanggo mod tidy清理与优化方法
LINUX如何开放防火墙端口_Linux firewalld与iptables开放端口命令【安全配置】
Windows服务无法启动错误1067是什么_进程意外终止的解决方法
Windows10如何重置此电脑_Windows10电脑重置方法【步骤】
LINUX怎么设置系统语言_LINUX修改中文环境
Win10如何更改开机密码_Windows10登录选项更改密码
VSC怎样用终端运行PHP_命令行执行脚本的步骤【教程】
Win10如何设置双wan路由器 Win10双wan路由器设置方法【指南】
Windows系统时间服务错误_W32Time服务修复与同步教学
php增删改查需要哪些扩展_开启mysqli或pdo扩展方法【说明】
Linux怎么查找死循环进程_Linux系统负载分析与进程彻底结束【教程】
c++的mutex和lock_guard如何使用 互斥锁保护共享资源【多线程】
Mac电脑如何恢复出厂设置_Mac抹掉数据并重装系统【安全指南】
Windows 11怎么设置默认解压软件_Windows 11为ZIP/RAR文件指定默认打开程序
Windows10如何更改任务栏高度_Win10解除锁定调整大小
Windows10系统更新错误0x80070002_Win10自动更新失败手动修复
Win11怎么关闭系统声音_Win11系统提示音静音设置【详解】
如何在同包不同文件中正确引用 Go 结构体
Python模块的__name__属性如何由导入方式决定?
Win11怎么修复系统文件_使用sfc命令修复Win11系统【技巧】
Win11如何设置系统语言_Win11系统语言切换教程【攻略】
Python配置文件操作教程_JSONINIYAML解析与应用实战
如何理解Go指针和内存分配关系_Go Pointer内存Model解析
Win11怎么关闭搜索历史 Win11清除搜索框最近记录【隐私】
c++中如何进行二进制文件读写_c++ read与write函数用法
Win11怎么忘记WiFi网络_Win11删除已保存无线连接【教程】
Mac的“预览”如何合并多个PDF_Mac文件处理技巧【效率】
Python与Docker容器化部署实战_镜像构建与CI/CD流程
Python脚本参数接收_sys与argparse解析【指导】
如何在 Go 中调用动态链接库(.so)中的函数
Win10系统更新错误0x80240034怎么办 Win10更新错误解决法【方法】
Win11怎么卸载Photos应用_Win11卸载Photos应用方法【教程】
Mac如何彻底清理浏览器缓存?(Safari与Chrome)
2026-01-03
致胜网络推广营销网专注海外推广十年,是谷歌推广.Facebook广告全球合作伙伴,我们精英化的技术团队为企业提供谷歌海外推广+外贸网站建设+网站维护运营+Google SEO优化+社交营销为您提供一站式海外营销服务。