C++ 怎么实现单例 C++ Meyer's Singleton线程安全写法【模式】
技术百科
尼克
发布时间:2026-01-27
浏览: 次 C++11起Meyers Singleton(局部静态变量版)是线程安全、简洁且生命周期自动管理的单例实现;标准保证其首次初始化原子性,编译器自动生成同步机制,无需手动加锁或指针管理。
直接说结论:C++11 及以后,用 Meyers Singleton(即局部静态变量版本)是线程安全、简洁且无需手动管理生命周期的单例写法——标准明确保证其初始化的线程安全性。
为什么 Meyers Singleton 天然线程安全?
C++11 标准规定:函数内局部静态变量的首次初始化是原子的,且编译

__cxa_guard_acquire 等)。这意味着多个线程同时首次调用 instance(),也只会有一个执行构造,其余阻塞等待,无需 std::mutex 或双重检查锁(DCLP)。
常见错误是误以为“静态局部变量 = 不加锁就可能竞争”,这是 C++11 之前的老认知,已过时。
getInstance() 的正确写法与关键细节
核心就是把单例对象声明为函数局部静态变量,并返回引用:
class Logger {
public:
static Logger& instance() {
static Logger instance_; // ✅ C++11 线程安全初始化
return instance_;
}
Logger(const Logger&) = delete;
Logger& operator=(const Logger&) = delete;
private:
Logger() = default; // 可设为 private,但不必显式 inline
};
- 必须返回
Logger&(引用),不能返回值(否则触发拷贝/移动,破坏单例语义) -
static Logger instance_;必须在函数体内定义,不能提至全局或类静态成员——那是老式写法,需手动同步 - 析构时机由实现定义(通常在 main() 返回后、线程结束前),但无需显式调用
atexit或管理 - 如果构造函数可能抛异常,首次调用会重复尝试(标准允许),需确保幂等或捕获处理
和传统静态指针单例对比的坑
老写法如 static Logger* instance_ = nullptr; + if (!instance_) instance_ = new Logger; 有多个隐患:
- 不加锁时多线程下可能 double-new(未定义行为)
- 加锁后仍需处理内存释放顺序、
atexit竞争、以及static对象析构时调用单例的崩溃风险(静态析构顺序不确定) - 无法利用 RAII 自动管理资源(比如文件句柄、网络连接),而 Meyers 版本的
Logger析构函数会被自动调用 - 模板化单例时,老写法容易因特化/ODR 违反出错;Meyers 写法天然支持模板(
template)static T& instance()
真正要注意的不是“怎么加锁”,而是别在 C++11+ 环境里倒退回去手写锁或指针管理——局部静态变量的线程安全是语言级保障,不是巧合。
# ai
# 这是
# 多个
# 自动生成
# 首次
# 那是
# 特化
# 设为
# 对象
# c++
# if
# double
# 指针
# 构造函数
# 同步机制
# 为什么
# 线程
# Static
# 多线程
# 析构函数
# 句柄
# 局部变量
# 加锁
# 保证其
相关栏目:
<?muma
$count = M('archives')->where(['typeid'=>$field['id']])->count();
?>
【
AI推广<?muma echo $count; ?>
】
<?muma
$count = M('archives')->where(['typeid'=>$field['id']])->count();
?>
【
SEO优化<?muma echo $count; ?>
】
<?muma
$count = M('archives')->where(['typeid'=>$field['id']])->count();
?>
【
技术百科<?muma echo $count; ?>
】
<?muma
$count = M('archives')->where(['typeid'=>$field['id']])->count();
?>
【
谷歌推广<?muma echo $count; ?>
】
<?muma
$count = M('archives')->where(['typeid'=>$field['id']])->count();
?>
【
百度推广<?muma echo $count; ?>
】
<?muma
$count = M('archives')->where(['typeid'=>$field['id']])->count();
?>
【
网络营销<?muma echo $count; ?>
】
<?muma
$count = M('archives')->where(['typeid'=>$field['id']])->count();
?>
【
案例网站<?muma echo $count; ?>
】
<?muma
$count = M('archives')->where(['typeid'=>$field['id']])->count();
?>
【
精选文章<?muma echo $count; ?>
】
相关推荐
- php本地部署后session无法保存_sessi
- php8.4xdebug无法调试怎么办_php8.
- Windows电脑键盘突然失灵怎么办?(驱动与硬件
- c++中如何对数组进行排序_c++数组排序算法汇总
- 如何在 Go 同包不同文件中正确引用结构体
- c++获取当前时间戳_c++ time函数使用详解
- PHP主流架构如何处理会话管理_Session与C
- Python性能剖析高级教程_cProfileLi
- C#怎么使用委托和事件 C# delegate与e
- PhpStorm怎么调试PHP代码_PhpStor
- Mac自带的词典App怎么用_Mac添加和使用多语
- VSC怎样在Linux运行PHP_Ubuntu系统
- ACF 教程:如何正确更新嵌套在多层 Group
- 如何高效删除 NumPy 二维数组中所有元素相同的
- 使用类变量定义字符串常量时如何实现类型安全的 Li
- mac怎么安装pip_MAC Python pip
- 静态属性修改会影响所有实例吗_php作用域操作符下
- Windows10无法识别USB设备描述符请求失败
- PHP的Workerman对架构扩展有啥帮助_应用
- Windows Defender扫描失败怎么办_安
- Win11怎么更改鼠标指针方案_Windows11
- Go语言中slice追加操作的底层共享机制解析
- Win11怎么设置闹钟_Windows 11时钟应
- Win11怎样彻底卸载自带应用_Win11彻底卸载
- c++20的std::format怎么用 比pri
- 如何在 Django 中修改用户密码后保持会话不丢
- Python并发安全问题_资源竞争说明【指导】
- 如何高效获取循环末次生成的 NumPy 数组最后一
- c++中的可变参数模板(variadic temp
- 如何使用Golang反射创建map对象_动态生成键
- Win10怎样清理C盘Steam游戏缓存_Win1
- Win11怎样安装企业微信_Win11安装企业微信
- Python高性能计算项目教程_NumPyCyth
- Win10如何更改开机密码_Windows10登录
- 如何在 ACF 中正确更新嵌套多层的 Group
- 如何在Golang中写入XML文件_生成符合规范的
- 如何使用Golang读取日志文件_Golang b
- Go 语言标准库为何不提供泛型切片的 Contai
- Win11相机打不开提示错误怎么修_相机权限开启与
- 如何在Golang中使用内置函数_Golangle
- Python集合操作技巧_高效去重解析【教程】
- PythonPandas数据分析项目教程_时间序列
- 如何使用Golang实现云原生应用弹性伸缩_自动应
- c++输入输出流 c++ cin与cout格式化输
- PHP主流架构怎么部署到Docker_容器化流程【
- php与c语言在嵌入式中有何区别_对比两者在硬件控
- windows 10应用商店区域怎么改_windo
- Win11怎么开启远程桌面_Win11系统远程桌面
- WindowsUSB驱动安装异常怎么办_USB驱动
- php增删改查需要哪些扩展_开启mysqli或pd

QQ客服