现在的位置: 首页 > 综合 > 正文

C++设计模式之Singleton(单件/单例)模式

2018年04月13日 ⁄ 综合 ⁄ 共 6459字 ⁄ 字号 评论关闭

单例模式,顾名思义,此模式下的对象实例永远只有一个.很多初学者感觉,这个模式的用处不大.但实际上,这个模式应该算是应用得最广泛的模式之一了.

很多情况下,我们需要考虑单例的实现方式.如全局内存池;全局资源管理器;某个全局的工具类工厂...在UI开发上,同一时间点上仅会出现一个实例的对话框,也可以使用单例实现.

单例的类图很简单:

它的目的就是,给程序提供一个全局唯一的访问点,用于访问某些资源;固定的算法或唯一的对象等.

单例模式的构建方式主要有两种:饿汉方式与懒汉方式.也就是静态初始化的单例与运行时根据需要初始化的单例.

  • 饿汉方式

  

  • 懒汉方式

当我们在实际应用中,很可能需要考虑线程安全问题.饿汉方式由于实现采用类成员静态初始化,始终是在主线程的主函数开始之前,以单线程方式进行的.所以当程序开启多个线程开始同步访问此单例类的时候,它总能返回唯一的单例.

然而懒汉方式则都是非线程安全的.就算是使用函数内部静态初始化的懒汉单例,由于目前的C++标准并没有规定编译器需要解决static的线程安全性,因此它也不是线程安全的.

也就是说,一个static声明的类变量,在多线程同时第一次访问时将有可能被构造多次(普通类型的变量,如bool,int的static是线程安全的.在C++0x中规定了static必须由编译器解决线程安全问题,因此支持C++0x的编译器编译的static类变量应该也不会有线程安全问题).

因此,我们可能需要这样来写线程安全的懒汉单例(注意,我这里使用的锁仅是语义上的"锁",在实际应用中需要使用对应平台提供的锁来完成相应操作):

  • 线程安全的懒汉方式

在实际项目中,很多时候我们会用泛型的思想做单例模式,例如如下代码:

  • 利用模板实现较为通用的单例

这是一个利用模板实现的饿汉单例,并且是线程安全的.其他方式实现的单例模式也可以类似推出对应的模板实现.

上面说了那么多,可以看出来,最方便的实现方式,应该是使用类成员静态初始化实现的饿汉方式单例了.但是这种单例模式有个最大的硬伤,就是在C++里默认的静态成员初始化顺序是不确定的.当一个程序中有多个单例,并且单例之间有相互的依赖时,就很可能出现因为构造顺序的不一致,导致当访问某些单例时出现返回的对象尚未初始化的问题.

解决的方法有很多种,在这里我一般是确定一个会被其他单例类依赖的单例,将它采用懒汉模式实现,而其他的单例则使用饿汉模式.此时的懒汉单例也不需要加锁,因为它必定会被其他的饿汉在构造的时候调用一次.


下面给出完整的示例代码:

抱歉!评论已关闭.