信息发布→ 登录 注册 退出

C++如何实现单例设计模式?C++最常用的设计模式讲解【架构入门】

发布时间:2025-12-16

点击量:
C++单例模式最安全写法是C++11起用局部静态变量实现,线程安全且自动管理生命周期;带参数时推荐静态局部变量+工厂函数,避免双重检查锁定陷阱;非必要场景应优先考虑依赖注入或全局对象。

c++如何实现单例设计模式?c++最常用的设计模式讲解【架构入门】

单例模式在C++中核心目标是:确保一个类只有一个实例,并提供全局访问点。它不难写,但容易写错——尤其在多线程、析构顺序和懒加载场景下。

最安全的现代C++写法(C++11起推荐)

利用局部静态变量的“首次调用时初始化”和线程安全特性,代码简洁且天然线程安全:

class Singleton {
public:
    static Singleton& getInstance() {
        static Singleton instance; // C++11保证:首次调用时构造,且线程安全
        return instance;
    }

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

private:
    Singleton() = default; // 私有构造,禁止外部创建
    ~Singleton() = default; // 析构可公开或私有,按需决定
};

✅ 优点:无锁、无内存泄漏风险、自动管理生命周期、符合RAII;
❌ 注意:析构时机由程序结束时静态对象销毁顺序决定,若其他静态对象依赖它,可能出问题(称为“静态初始化顺序惨案”)。

带参数的单例(延迟构造 + 参数传递)

如果构造函数需要参数(比如配置路径、日志级别),不能直接用静态局部变量。常用方案是“双重检查锁定 + 智能指针”:

#include <memory>
#include <mutex>

class ConfigurableSingleton {
public:
    static ConfigurableSingleton& getInstance(const std::string& configPath) {
        // 第一次检查(无锁,快速返回)
        if (instance_ != nullptr) {
            return *instance_;
        }

        std::lock_guard<std::mutex> lock(mutex_);
        // 第二次检查(加锁后再次确认)
        if (instance_ == nullptr) {
            instance_ = std::make_unique<ConfigurableSingleton>(configPath);
        }
        return *instance_;
    }

    static void destroy() {
        std::lock_guard<std::mutex> lock(mutex_);
        instance_.reset();
    }

private:
    explicit ConfigurableSingleton(const std::string& path) {
        // 加载配置等耗时操作
    }

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

    static std::unique_ptr<ConfigurableSingleton> instance_;
    static std::mutex mutex_;
};

// 定义静态成员
std::unique_ptr<ConfigurableSingleton> ConfigurableSingleton::instance_;
std::mutex ConfigurableSingleton::mutex_;

⚠️ 注意:必须手动调用 destroy() 避免程序退出前未释放资源;若不想手动管理,可改用静态局部变量+工厂函数封装参数(更推荐)。

S-CMS企业建站系统(含APP/小程序)5.0 build20230614 S-CMS企业建站系统(含APP/小程序)5.0 build20250614

闪灵CMS企业建站系统是淄博闪灵网络科技有限公司开发的一款专门为企业建站提供解决方案的产品,前端模板样式主打HTML5模板,以动画效果好、页面流畅、响应式布局为特色,程序主体采用PHP+MYSQL构架,拥有独立自主开发的一整套函数、标签系统,具有极强的可扩展性,设计师可以非常简单的开发出漂亮实用的模板。系统自2015年发布第一个版本以来,至今已积累上万用户群,为上万企业提供最优质的建站方案。

S-CMS企业建站系统(含APP/小程序)5.0 build20230614 0 查看详情 S-CMS企业建站系统(含APP/小程序)5.0 build20230614

常见误写与陷阱

  • 手写 double-checked locking(DCLP)不用 memory_order:C++11前易出错,现在应优先用 std::call_once 或静态局部变量
  • 用 new 分配但忘了 delete:导致内存泄漏;建议统一用 std::unique_ptr 管理
  • 把 getInstance 声明为 const 成员函数:错误!获取实例本身是可变操作(首次构造会修改状态)
  • 在构造函数里调用 getInstance:引发死锁或未定义行为(递归初始化静态变量)

什么情况下不该用单例?

单例不是万能解药。以下情况建议绕开:

  • 只是想共享数据 → 用普通全局变量或命名空间内静态对象更轻量
  • 需要多种配置的多个实例(如多个数据库连接)→ 改用工厂 + 对象池
  • 测试困难(全局状态干扰单元测试)→ 考虑依赖注入(传入接口引用)
  • 模块间强耦合 → 单例会隐式引入依赖,破坏可维护性

基本上就这些。单例本身不复杂,但用得是否恰当,往往暴露架构思考深度。

以上就是C++如何实现单例设计模式?C++最常用的设计模式讲解【架构入门】的详细内容,更多请关注其它相关文章!


相关文章: PHP中获取MongoDB服务器运行时间(Uptime)的专业指南  C++的std::mdspan是什么_C++23中用于操作多维数组的非拥有视图  Win11输入法不见了怎么办_Windows11恢复语言栏显示方法  星露谷物语官网入口 星露谷物语游戏官网入口  sublime怎么预览Markdown渲染效果_Markdown Preview插件 for sublime教程  QQ邮箱在线登录平台 QQ邮箱个人邮箱网页版入口  将HTML动态表格多行数据保存到Google Sheet的教程  composer的"require-dev"部分是用来做什么的?  腾讯视频怎么使用多账号家庭管理_腾讯视频家庭多账号统一管理与权限分配教程  C++20的source_location是什么_C++在编译期获取源码位置信息用于日志和断言  Python Socket多播通信中指定源IP地址的实践指南  CSS条件样式无法按设备触发怎么排查_media条件语句正确设置解决触发问题  HTML元素状态管理:根据DIV内容动态启用/禁用按钮  HTML空白字符处理机制:渲染、DOM与编码实践  解决macOS上安装pyhdf时‘hdf.h’文件缺失的编译错误  大麦的“候补”是什么意思 大麦候补购票规则【详解】  如何设置Windows Defender的定时扫描_计划任务实现自动杀毒【安全】  Python中高效访问嵌套字典与列表中的键值对  PHP教程:高效从URL路径中提取倒数第二个片段  PHP文件上传至S3:策略、考量与避免本地存储的挑战  2025AO3夸克浏览器通道_AO3手机HTTPS安全入口分享  Log4j Console Appender性能瓶颈与高并发优化策略  AO3最新入口2025公告_AO3中文官网合集  GemBox Document HTML转PDF垂直文本渲染问题及解决方案  海棠账号登录入口_登录海棠账户同步阅读记录  outlook中文官网入口地址 outlook官方中文版直达首页链接  邮编格式怎么匹配地址_根据邮编格式快速匹配详细地址的技巧  Lar*el 8 多关键词数据库搜索优化实践  Centos/Linux 系统下安装 composer 的完整步骤  Lar*el DB::listen 事件中的查询执行时间单位解析  Safari怎么安装扩展程序 浏览器插件安装与管理方法【详解】  魅族20怎样在浏览器开无图省流_iPhone魅族20浏览器开无图省流【流量节省】  拼多多视频播放卡顿如何处理 拼多多视频播放优化技巧  谷歌学术网站直达地址 谷歌学术搜索网页版一键进入  蛙漫2日版入口 WAMAN2(日版)无删减漫画官网链接  PPT平滑切换怎么做 PPT炫酷“平滑”切换动画制作教程【必学】  树莓派传感器触发:通过Twilio API发送WhatsApp消息教程  vivo手机参数配置怎么增强信号_vivo手机参数配置信号增强方法  c++中为什么推荐使用using替代typedef_c++现代化类型别名  Node.js CSV 数据处理:基于字段空值条件过滤整条记录的策略  MAC如何安全彻底地删除文件_MAC使用终端命令确保文件无法被恢复  解决Bootstrap卡片顶部边距导致背景图下移的问题  Highcharts 雷达图径向轴标签定制指南:利用多Y轴实现数值标注  qq音乐在线播放入口_qq音乐电脑版登录链接  MongoDB Aggregation:在嵌套对象数组中精确匹配ObjectId  Win11 USB传输速度慢怎么解决 Win11 USB驱动更新与设置  在Go开发中优雅管理ListenAndServe进程:GoSublime集成方案  微博网页版官方账号登录 微博网页版内容浏览使用指南  Mac怎么锁定备忘录_Mac备忘录加密设置教程  淘宝支付提示失败如何解决 淘宝支付流程优化方法 

在线客服
服务热线

服务热线

4008988990

微信咨询
二维码
返回顶部
×二维码

截屏,微信识别二维码

打开微信

微信号已复制,请打开微信添加咨询详情!