C++实现单件模式Singleton Pattern

单件模式确保一个类只有一个实例,并提供一个全局访问点。


懒汉模式:

顾名思义,他是一个懒汉,他不愿意动弹。什么时候需要吃饭了,他就什么时候开始想办法搞点食物。
即懒汉式一开始不会实例化,什么时候用就什么时候new,才进行实例化。

说明: 先不创建实例,当第一次被调用时,再创建实例,所以被称为懒汉式。

优点: 延迟了实例化,如果不需要使用该类,就不会被实例化,节约了系统资源。

缺点: 线程不安全,多线程环境下,如果多个线程同时进入了 if (uniquerSingleton== null) ,若此时还未实例化,也就是uniquerSingleton== null,那么就会有多个线程执行 uniquerSingleton= new LazySingleton(); ,就会实例化多个实例;
与之相反的是饿汉式(线程安全)

#include <iostream>

class LazySingleton {
private:
    //利用一个静态变量来记录Singleton类的唯一实例
    static LazySingleton *uniquerSingleton;
public:
    void print() {
        printf("Lazy Singleton\n");
    }
    static LazySingleton* getInstance() {//将构造器声明为私有,只有来自Singleton类内才可以调用构造器
        if (uniquerSingleton == nullptr) {
            /*如果对象不存在,就利用私有构造器产生 一个实例,
            并把它赋值到uniquerSingleton静态变量中,
            如果我们不需要,它就永远不会产生,这就是延迟实例化*/
            uniquerSingleton = new LazySingleton();
        }
        return uniquerSingleton;
    }
};
LazySingleton* LazySingleton::uniquerSingleton = nullptr;

int main(){
    LazySingleton* ls = LazySingleton::getInstance();
    ls->print();
    return 0;
}

饿汉模式:

顾名思义,他是一个饿汉,他很勤快就怕自己饿着。他总是先把食物准备好,什么时候需要吃了,他随时拿来吃,不需要临时去搞食物。
即饿汉式在一开始类加载的时候就已经实例化,并且创建单例对象,以后只管用即可。

说明: 实现和 线程不安全的懒汉式 几乎一样,唯一不同的点是,在get方法上 加了一把 锁。如此一来,多个线程访问,每次只有拿到锁的的线程能够进入该方法,避免了多线程不安全问题的出现。

优点: 延迟实例化,节约了资源,并且是线程安全的

缺点: 虽然解决了线程安全问题,但是性能降低了。当这个对象特别大的时候,无论你用不用该对象,在使用程序开始的那一课开始,对象已经存在,会造成巨大的内存浪费。

#include <iostream>
class HungrySingleton {
    //利用一个静态变量来记录Singleton类的唯一实例
public:
    static HungrySingleton* uniquerSingleton;
    void print() {
        printf("Hungry Singleton\n");
    }
    static HungrySingleton* getInstance() {//将构造器声明为私有,只有来自Singleton类内才可以调用构造器
        return uniquerSingleton;
    }
};

//类外进行初始化
HungrySingleton* HungrySingleton::uniquerSingleton = new HungrySingleton;
int main(){
    HungrySingleton::uniquerSingleton->print();
    return 0;
}

懒汉式和饿汉式的安全和性能区别:
(1) 线程安全:饿汉式在线程还没出现之前就已经实例化了,所以饿汉式一定是线程安全的。懒汉式加载是在使用时才会去new 实例的,那么你去new的时候是一个动态的过程,是放到方法中实现的。
        如果这个时候有多个线程访问这个实例,这个时候实例还不存在,还在new,就会进入到方法中,有多少线程就会new出多少个实例。一个方法只能return一个实例,那最终return出哪个呢?是不是会覆盖很多new的实例?这种情况当然也可以解决,那就是加同步锁,避免这种情况发生 。

(2)执行效率:饿汉式没有加任何的锁,因此执行效率比较高。懒汉式一般使用都会加同步锁,效率比饿汉式差。
(3)内存使用:饿汉式在一开始类加载的时候就实例化,无论使用与否,都会实例化,所以会占据空间,浪费内存。懒汉式什么时候用就什么时候实例化,不浪费内存。
 


双重锁:线程安全的懒汉模式

#include <iostream>
#include <mutex>

std::mutex mt;
class SingleTon {
public:
	static SingleTon* getInstance() {
		if (m_instance == nullptr) {
			mt.lock();
			if (m_instance == nullptr) {
				m_instance = new SingleTon;
			}
			mt.unlock();
		}
		return m_instance;
	}
	~SingleTon() {
		printf("~SingleTon() called!\n");
	}
	void print() {
		if (m_instance == nullptr) {
			printf("m_instance == nullptr\n");
		}
		printf("SingleTon!!!\n");
	}
private:
	static SingleTon* m_instance;
};
SingleTon* SingleTon::m_instance = nullptr;

int main(int* argc, int* argv[]) {
	SingleTon* singleTon = nullptr;
	singleTon = SingleTon::getInstance();
	singleTon->print();
	SingleTon* hehe = nullptr;
	hehe = SingleTon::getInstance();
	hehe->print();
	delete singleTon;
	return 0;
}

参考:

1. EricFreeman, FreemanElisabeth, 弗里曼, et al. Head First设计模式[M]. 中国电力出版社, 2007.

2. 单例模式中的懒汉模式和饿汉模式是什么?区别又是什么?

3. 设计模式05—单件模式

4. 【C++】单例模式(懒汉、饿汉)

5. C++单例模式的懒汉模式和饿汉模式详解

6. C++设计模式-单例模式(双重锁定)

评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值