【设计模式】单例模式

1. 什么是单例模式

  该模式的主要目的就是确保某个类有且仅有一个实例存在,在任何位置都可以通过接口获取这个唯一实例。如:

  • 设备管理器:系统可以有多个设备,但是只有一个设备管理器,用于管理设备驱动;
  • 数据池:用来缓存数据的数据结构,需要在一处写,多处读取,或者多处写,多处读取;

2. 单例模式的应用

  • 特征

  1. 确保全局只有一个实例(static private)被创建:

    为此,单例类只能提供私有(private)构造函数,保证用户不能随意自定义实例;实例靠自己来创建;

  2. 提供该实例的全局访问接口:

    通过静态(static)公有方法,创建或者获取该静态私有对象;

  3. 禁止赋值和拷贝

  4. 线程安全

  • 如何使用

  越小越好,越简单越好,线程安全,内存不泄露。

3. 单例模式的几种实现及优缺点

  • 懒汉式:懒汉很懒,只有用的时候才实例化

  写法1:(基础写法,有缺陷)

复制代码

class Singleton
{
private:
  static Singleton* instance;


private:
  Singleton() {};
  ~Singleton() {};
  Singleton(const Singleton&) = delete; //C++11特性,不允许调用该函数
  Singleton& operator=(const Singleton&) = delete;


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

// init static member
Singleton* Singleton::instance = NULL;

复制代码

  这是个最基础的单例模式实现,他有那些问题呢?

  • 线程安全问题,如多个线程同时尝试获取单例,判断m_pInstance都为空,实例化多个对象。解决方法:加锁
  • 内存是否泄漏?只负责new出对象,却不负责delete对象,导致内存泄漏?一般而言,单例类实例都是常驻的,不需要手动释放。如果非要释放,不能在析构函数中,可以考虑增加一个destroy()方法,或者智能指针;

  写法2:(安全写法,也有不足)

复制代码
class Singleton
{
public:
typedef std::shared_ptr<Singleton> sharePtr;
~Singleton() {} Singleton(Singleton&) = delete; Singleton& operator=(const Singleton&) = delete; static sharePtr getInstance() { //double checked lock if(!m_pInstance) { std::lock_guard<std::mutex> lk(m_mutex); if(!m_pInstance)   m_pInstance = std::shared_ptr<Singleton>(new Singleton); } return m_instance_ptr; } private: Singleton() {} static sharePtr m_pInstance; static std::mutex m_mutex; }; Singleton::sharePtr Singleton::m_pInstance = NULL; std::mutex Singleton::m_mutex;
复制代码

  不足之处在于:

  • 约束用户也要使用只能指针,非必要不约束;
  • 锁也有开销,大数据量情况下,会成为严重的性能瓶颈
  • 代码增多;
  • 某些平台(编译器和指令架构不同),双检锁会失效;

  写法3:(最推荐写法,局部静态变量 - magic static)

复制代码

class Singleton
{
private:
  Singleton() {};
  ~Singleton() {};
  Singleton(const Singleton&) = delete;
  Singleton& operator=(const Singleton&) = delete;

public:
  static Singleton& getInstance()
  {
    static Singleton instance;
    return instance;
  }
};

复制代码

  又叫做Meyers' SingletonMeyer's的单例,是著名《Effective C++》作者Meyers提出的,用到的特性是C++11中的Magic Static特性: 

If control enters the declaration concurrently while the variable is being initialized, the concurrent execution shall wait for completion of the initialization.
如果当变量在初始化的时候,并发同时进入声明语句,并发线程将会阻塞等待初始化结束。

  这样保证了并发线程在获取静态局部变量的时候一定是初始化过的,所以具有线程安全性:

  • 通过局部静态变量特性,保证了线程安全(C++11,GCC>4.3,VS2015)
  • 不需要共享指针,代码简洁;
  • 注意使用时,需要声明单例的引用才能获取对象;否则返回指针的话,无法避免用户delete导致对象提前销毁。

  写法4:单例模板

  待续。。。

 

C++ 单例模式总结与剖析 - 行者孙 - 博客园 (cnblogs.com)

posted @   hik_wxy  阅读(82)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 阿里最新开源QwQ-32B,效果媲美deepseek-r1满血版,部署成本又又又降低了!
· Manus重磅发布:全球首款通用AI代理技术深度解析与实战指南
· 开源Multi-agent AI智能体框架aevatar.ai,欢迎大家贡献代码
· 被坑几百块钱后,我竟然真的恢复了删除的微信聊天记录!
· AI技术革命,工作效率10个最佳AI工具
点击右上角即可分享
微信分享提示