单例模式 创建型模式之一

一句话来说就是,某个类只能有一个实例,提供一个全局的访问点。

单例模式的要点有三个:一是某个类只能有一个实例;二是它必须自行创建这个实例;三是它必须自行向整个系统提供这个实例。

为什么需要单例模式

两个原因:

  1. 节省资源。一个类只有一个实例,不存在多份实例,节省资源。
  2. 方便控制。在一些操作公共资源的场景时,避免了多个对象引起的复杂操作。

应用场景:

1.数据库连接,一般整个程序里面只需要进行一次数据库连接即可,后续就不需要再关闭后连接了。

2.日志:只需要声明一个日志对象,任何时候程序只往一个日志内填写

单例模式包括哪些类型:

主要两大类:

1.懒汉式

2.饿汉式

二、单例的种类有哪些?之间有什么区别?

懒汉式:指全局的单例实例在第一次被使用时构建。
饿汉式:全局的单例实例在类装载(ClassLoader)时构建。(饿汉式单例性能优于懒汉式单例)
1、懒汉式与饿汉式区别:

        1.1懒汉式默认不会实例化,外部什么时候调用什么时候new。饿汉式在类加载的时候就实例化,并且创建单例对象。

        1.2、懒汉式是延时加载,在需要的时候才创建对象,而饿汉式是在虚拟机启动的时候就会创建。

        1.3、懒汉式在多线程中是线程不安全的,而饿汉式是不存在多线程安全问题的。

懒汉式的线程安全问题:

线程安全的问题,当多线程获取单例时有可能引发竞态条件:第一个线程在if中判断 m_pInstance是空的,于是开始实例化单例;同时第2个线程也尝试获取单例,这个时候判断m_pInstance还是空的,于是也开始实例化单例;这样就会实例化出两个对象,这就是线程安全问题的由来; 解决办法:加锁
内存泄漏. 注意到类中只负责new出对象,却没有负责delete对象,因此只有构造函数被调用,析构函数却没有被调用;因此会导致内存泄漏。解决办法: 使用共享指针;

由于懒汉模式存在多线程的安全问题,因此会衍生出线程安全的懒汉式

其中一种方式就是使用智能指针和线程锁

另外一种方式是使用局部静态变量

这种方法又叫做 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++静态变量的生存期 是从声明到程序结束,这也是一种懒汉式。

这是最推荐的一种单例实现方式:通过局部静态变量的特性保证了线程安全 , 不需要使用共享指针,代码简洁;注意在使用的时候需要声明单例的引用 Single& 才能获取对象。

当然,C++11 后面出现std::call_once 就是解决这个问题,但是没有magic static 方便,所以推荐magic static的使用方法 。

引用:

2.5 万字详解:23 种设计模式 - 知乎 (zhihu.com)

【C++】C++ 单例模式总结(5种单例实现方法)_单例模式c++实现-CSDN博客
设计模式——单例模式(懒汉式与饿汉式)详解_懒汉式饿汉式是啥设计模式啊?-CSDN博客

C++ 单例模式-CSDN博客

你可能感兴趣的:(单例模式)