当前位置: 首页 > news >正文

c++单例模式(Singleton)多种实现方式及最优比较

前言

关于C++单例模式的写法,大家都很熟悉。早期的设计模式中有代码示例。比如:

class Singleton {private: static Singleton *instance;public: static Singleton *getInstance() {if (NULL == instance)instance = new Singleton();return instance;}
};

它的缺点:线程不安全,指针资源没有释放。

自从C++11推出后,单例模式有了更优秀的写法,下面来介绍下。

使用 std::call_once 实现

#include <iostream>
#include <mutex>
#include <memory>class Singleton {
private:Singleton() { std::cout << "Singleton constructed." << std::endl; }static std::once_flag initInstanceFlag;static std::unique_ptr<Singleton> instance;// 删除拷贝构造函数和赋值操作符Singleton(const Singleton&) = delete;Singleton& operator=(const Singleton&) = delete;public:static Singleton& getInstance() {std::call_once(initInstanceFlag, []() {instance.reset(new Singleton());});return *instance;}void someMethod() {std::cout << "Method of the singleton" << std::endl;}~Singleton() {std::cout << "Singleton destructed." << std::endl;}
};std::once_flag Singleton::initInstanceFlag;
std::unique_ptr<Singleton> Singleton::instance;// 使用示例
void threadFunction() {Singleton& singleton = Singleton::getInstance();singleton.someMethod();
}int main() {std::thread t1(threadFunction);std::thread t2(threadFunction);t1.join();t2.join();return 0;
}

优点:线程安全、内存安全。显式控制初始化过程,适合需要延迟初始化的场景。

使用局部静态变量实现(C++11及以后)

#include <iostream>
#include <memory>class Singleton {
private:Singleton() { std::cout << "Singleton constructed." << std::endl; }// 关闭拷贝构造函数、右值拷贝构造函数和赋值操作符Singleton(const Singleton&) = delete;Singleton(const Singleton &&) = delete;Singleton& operator=(const Singleton&) = delete;public:static Singleton& getInstance() {static Singleton instance;return instance;}void someMethod() {std::cout << "Method of the singleton" << std::endl;}~Singleton() {std::cout << "Singleton destructed." << std::endl;}
};// 使用示例
void threadFunction() {Singleton& singleton = Singleton::getInstance();singleton.someMethod();
}int main() {std::thread t1(threadFunction);std::thread t2(threadFunction);t1.join();t2.join();return 0;
}

优点:线程安全。代码最简洁,由C++11标准保证线程安全,适合大多数场景。
缺点:适用于不复杂的工程。因为如果静态类之间有依赖,可能会导致C++的一些未定义的行为。

Meyers 的版本

Scott Meyers 是 Effective C++系列的作者,他最早提供了简洁版本的 Singletion 模型。根据他提供的模型,可以写出线程安全又简单的单例模式。代码如下:

#include <stdio.h>class singleton {static singleton &instance() {static singleton instance;return instance;} // instancesingleton(const singleton &) = delete;singleton & operator = (const singleton &) = delete;private:singleton() {}~singleton() {}public:void out(){ printf("out\n"); }
}; // struct singletonint main() {singleton::instance().out();return 0;
}

缺点:单一的实例总是在 main() 开始之前被初始化的,该实现无法做到 lazyinit。
优化版本:

 template<typename T>class singleton {public:static T &instance();singleton(const singleton &) = delete;singleton &operator=(const singleton) = delete;protected:singleton() = default;};template<typename T>inline T &singleton<T>::instance() {static const std::unique_ptr<T> instance{new T{token{}}};return *instance;}

优点:线程安全、内存安全。

鸿蒙单例实现

线程安全、内存安全、延迟加载、支持lazyinit、实现单例模板。当前在使用中,代码可靠。
使用说明,请点这里。
下面只展示DelayedSingleton实现示例。完整代码以及其它几种单例实现,请点这里。

template<typename T>
class DelayedSingleton : public NoCopyable {
public:static std::shared_ptr<T> GetInstance();static void DestroyInstance();private:static std::shared_ptr<T> instance_;  instance.static std::mutex mutex_; 
};template<typename T>
std::shared_ptr<T> DelayedSingleton<T>::instance_ = nullptr;template<typename T>
std::mutex DelayedSingleton<T>::mutex_;template<typename T>
std::shared_ptr<T> DelayedSingleton<T>::GetInstance()
{if (instance_ == nullptr) {std::lock_guard<std::mutex> lock(mutex_);if (instance_ == nullptr) {std::shared_ptr<T> temp(new (std::nothrow) T);instance_ = temp;}}return instance_;
}template<typename T>
void DelayedSingleton<T>::DestroyInstance()
{std::lock_guard<std::mutex> lock(mutex_);if (instance_ != nullptr) {instance_.reset();instance_ = nullptr;}
}

相关文章:

  • 北京网站建设多少钱?
  • 辽宁网页制作哪家好_网站建设
  • 高端品牌网站建设_汉中网站制作
  • 打手机检测算法源码样本展示打手机检测算法实际应用场景介绍
  • sort排序免忘记
  • 云轴科技ZStack产品升级,浙江分公司产品发布会成功举办
  • chrome cookie编辑
  • 如何选择适合海外直播的网络?
  • 万亿生成式AI市场,商汤迎来“长坡厚雪”
  • 【React原理 - 任务调度和时间分片详解】
  • Maui的xaml中的换行符
  • Linux--IO模型_多路转接
  • k8s的组件以及安装
  • 【Linux】 理解 Linux 中的 `dup2` 函数
  • 关于一个早期对电子辐射的小讨论
  • 回调与观察者模式区分
  • 机器视觉--光源打光技巧
  • 大数据技术之HBase简介(1)
  • angular组件开发
  • iOS帅气加载动画、通知视图、红包助手、引导页、导航栏、朋友圈、小游戏等效果源码...
  • Java程序员幽默爆笑锦集
  • java架构面试锦集:开源框架+并发+数据结构+大企必备面试题
  • js中的正则表达式入门
  • Laravel 菜鸟晋级之路
  • MQ框架的比较
  • React中的“虫洞”——Context
  • windows-nginx-https-本地配置
  • 计算机在识别图像时“看到”了什么?
  • 问:在指定的JSON数据中(最外层是数组)根据指定条件拿到匹配到的结果
  • 转载:[译] 内容加速黑科技趣谈
  • C# - 为值类型重定义相等性
  • 扩展资源服务器解决oauth2 性能瓶颈
  • $con= MySQL有关填空题_2015年计算机二级考试《MySQL》提高练习题(10)
  • (二)PySpark3:SparkSQL编程
  • (附源码)ssm户外用品商城 毕业设计 112346
  • (牛客腾讯思维编程题)编码编码分组打印下标(java 版本+ C版本)
  • (实战)静默dbca安装创建数据库 --参数说明+举例
  • (转)shell调试方法
  • .Net Attribute详解(上)-Attribute本质以及一个简单示例
  • .NET Framework与.NET Framework SDK有什么不同?
  • .NET 命令行参数包含应用程序路径吗?
  • .sh
  • @Mapper作用
  • @Repository 注解
  • []FET-430SIM508 研究日志 11.3.31
  • [ai笔记4] 将AI工具场景化,应用于生活和工作
  • [Android Pro] android 混淆文件project.properties和proguard-project.txt
  • [BJDCTF2020]The mystery of ip
  • [C++] 轻熟类和对象
  • [C++核心编程](四):类和对象——封装
  • [CTO札记]如何测试用户接受度?
  • [flutter]一键将YAPI生成的api.json文件转为需要的Dart Model类的脚本
  • [FreeRTOS 基础知识] 栈
  • [HDU5685]Problem A
  • [Hive] 常见函数
  • [javaee基础] 常见的javaweb笔试选择题含答案
  • [JavaScript] JavaScript事件注册,事件委托,冒泡,捕获,事件流
  • [Linux] Linux入门必备的基本指令(不全你打我)