0

0

c++如何实现各种设计模式之单例_c++ 静态局部变量实现的线程安全【案例】

冰火之心

冰火之心

发布时间:2025-12-31 08:11:32

|

539人浏览过

|

来源于php中文网

原创

C++11起最简可靠的单例实现是函数内static局部变量,天然线程安全、懒加载、自动析构;需删除拷贝/移动操作符;优于std::call_once+指针或全局static变量。

c++如何实现各种设计模式之单例_c++ 静态局部变量实现的线程安全【案例】

单例模式在 C++11 之后用 static 局部变量最简实现

只要编译器支持 C++11(如 GCC 4.8+、Clang 3.3+、MSVC 2015+),static 局部变量的初始化天然线程安全,无需手动加锁或双重检查。这是目前最推荐、最简洁、最可靠的单例写法。

原因在于:C++11 标准明确要求,static 局部变量的首次初始化必须是原子的,编译器会自动生成保护逻辑(如 GCC 用 __cxa_guard_acquire 等机制)。

  • 不依赖 std::call_oncestd::mutex,无额外依赖和性能开销
  • 自动满足“懒加载”(首次调用 instance() 时才构造)
  • 析构由运行时在程序退出时自动管理,顺序符合静态对象规则
  • 禁止拷贝/移动:需显式删除 copy constructorassignment operatormove 相关函数
class Logger {
public:
    static Logger& instance() {
        static Logger inst;  // ✅ C++11 起线程安全
        return inst;
    }
void log(const std::string& msg) { /* ... */ }

private: Logger() = default; ~Logger() = default;

Logger(const Logger&) = delete;
Logger& operator=(const Logger&) = delete;
Logger(Logger&&) = delete;
Logger& operator=(Logger&&) = delete;

};

为什么不用 std::call_once + static 指针?

这种写法(也叫“Meyers 单例”的变体)虽然可行,但多此一举,且容易出错:

立即学习C++免费学习笔记(深入)”;

  • std::call_once 增加了不必要的函数调用开销和状态管理(std::once_flag
  • 手动 new 出的对象不会自动析构,必须显式注册 atexit 或靠 std::shared_ptr 管理,否则泄漏
  • 若忘记删除拷贝/移动函数,可能意外复制出多个实例
  • 相比 static 局部变量,代码更长、可读性更低、出错面更大

除非你被迫使用 C++03 编译器(已极少见),否则完全没必要走这条路。

Contentfries
Contentfries

将长视频改造成更加引人注目的短视频

下载

常见误用:把 static 变量声明在类外或全局作用域

以下写法看似简单,实则破坏单例语义或引入线程风险:

  • static Logger g_logger; → 全局对象,非懒加载;多个翻译单元中可能重复定义(ODR 违反);初始化顺序不可控
  • static Logger* p_inst = nullptr; → 首次赋值非原子,多线程下可能多次构造
  • 在头文件中定义 inline static Logger inst;(C++17)→ 虽线程安全且懒加载,但不如局部 static 直观,且部分旧工具链支持不佳

坚持用函数内 static 局部变量,是最小、最可控、标准保证最充分的选择。

注意:静态局部变量的析构时机与生命周期

析构发生在主线程退出、main() 返回之后,且按构造逆序执行。这意味着:

  • 其他静态对象的析构函数中调用 Logger::instance() 是未定义行为(可能已被析构)
  • 若单例内部持有对其他静态对象的引用(尤其是跨编译单元),可能出现“静态析构顺序惨案”(Static Initialization Order Fiasco 的反向版本)
  • 日志类等基础设施建议避免在析构阶段做复杂操作(如刷盘、网络发送),以防崩溃或死锁

真正健壮的单例不是“写出来就行”,而是得想清楚它活到什么时候、跟谁一起活、谁先死谁后死——这点比线程安全更常被忽略。

相关专题

更多
线程和进程的区别
线程和进程的区别

线程和进程的区别:线程是进程的一部分,用于实现并发和并行操作,而线程共享进程的资源,通信更方便快捷,切换开销较小。本专题为大家提供线程和进程区别相关的各种文章、以及下载和课程。

469

2023.08.10

Python 多线程与异步编程实战
Python 多线程与异步编程实战

本专题系统讲解 Python 多线程与异步编程的核心概念与实战技巧,包括 threading 模块基础、线程同步机制、GIL 原理、asyncio 异步任务管理、协程与事件循环、任务调度与异常处理。通过实战示例,帮助学习者掌握 如何构建高性能、多任务并发的 Python 应用。

106

2025.12.24

Python 多线程与异步编程实战
Python 多线程与异步编程实战

本专题系统讲解 Python 多线程与异步编程的核心概念与实战技巧,包括 threading 模块基础、线程同步机制、GIL 原理、asyncio 异步任务管理、协程与事件循环、任务调度与异常处理。通过实战示例,帮助学习者掌握 如何构建高性能、多任务并发的 Python 应用。

106

2025.12.24

Python 多线程与异步编程实战
Python 多线程与异步编程实战

本专题系统讲解 Python 多线程与异步编程的核心概念与实战技巧,包括 threading 模块基础、线程同步机制、GIL 原理、asyncio 异步任务管理、协程与事件循环、任务调度与异常处理。通过实战示例,帮助学习者掌握 如何构建高性能、多任务并发的 Python 应用。

106

2025.12.24

default gateway怎么配置
default gateway怎么配置

配置default gateway的步骤:1、了解网络环境;2、获取路由器IP地址;3、登录路由器管理界面;4、找到并配置WAN口设置;5、配置默认网关;6、保存设置并退出;7、检查网络连接是否正常。本专题为大家提供相关的文章、下载、课程内容,供大家免费下载体验。

219

2023.12.07

excel制作动态图表教程
excel制作动态图表教程

本专题整合了excel制作动态图表相关教程,阅读专题下面的文章了解更多详细教程。

24

2025.12.29

freeok看剧入口合集
freeok看剧入口合集

本专题整合了freeok看剧入口网址,阅读下面的文章了解更多网址。

74

2025.12.29

俄罗斯搜索引擎Yandex最新官方入口网址
俄罗斯搜索引擎Yandex最新官方入口网址

Yandex官方入口网址是https://yandex.com;用户可通过网页端直连或移动端浏览器直接访问,无需登录即可使用搜索、图片、新闻、地图等全部基础功能,并支持多语种检索与静态资源精准筛选。本专题为大家提供相关的文章、下载、课程内容,供大家免费下载体验。

207

2025.12.29

python中def的用法大全
python中def的用法大全

def关键字用于在Python中定义函数。其基本语法包括函数名、参数列表、文档字符串和返回值。使用def可以定义无参数、单参数、多参数、默认参数和可变参数的函数。本专题为大家提供相关的文章、下载、课程内容,供大家免费下载体验。

16

2025.12.29

热门下载

更多
网站特效
/
网站源码
/
网站素材
/
前端模板

精品课程

更多
相关推荐
/
热门推荐
/
最新课程
React 教程
React 教程

共58课时 | 3.1万人学习

Pandas 教程
Pandas 教程

共15课时 | 0.9万人学习

ASP 教程
ASP 教程

共34课时 | 3万人学习

关于我们 免责申明 举报中心 意见反馈 讲师合作 广告合作 最新更新
php中文网:公益在线php培训,帮助PHP学习者快速成长!
关注服务号 技术交流群
PHP中文网订阅号
每天精选资源文章推送

Copyright 2014-2025 https://www.php.cn/ All Rights Reserved | php.cn | 湘ICP备2023035733号