C++对单例模式实现的总结(C++11超简化版!!!必看精髓)

目录

1、饿汉模式(一开始就初始化单例对象)

2、懒汉模式(需要的时候在实例化单例对象)

3、C++11简化版(必看精髓)

4、单例模板


1、饿汉模式(一开始就初始化单例对象)

优点:不用担心多线程问题。

缺点:可能在整个程序中就没有用到这个单例对象,造成浪费。

实现:

class Singleton
{
public:
	static Singleton* GetInstance()//公有static方法,用于获取单例句柄
	{
		return &singleton_;
	}
private:
	Singleton();//构造函数私有
	static Singleton singleton_ ;//私有static单例对象
};


Singleton Singleton::singleton_;
int main()
{
	auto p1 = Singleton::GetInstance();
	auto p2 = Singleton::GetInstance();
	bool result=( p1 == p2);//判断是否指向同一个单例对象
	std::cout <<  result << std::endl;

	return 0;
}

2、懒汉模式(需要的时候在实例化单例对象)

优点:不会像饿汉模式一样造成资源浪费。只是需要考虑多线程安全,实现上稍稍复杂一点。

class Singleton
{
public:
	static Singleton* GetInstance()
	{
		if (p_singleton_ == nullptr)//第一次检查:实例化单例对象后,就不会再进入加锁逻辑
		{
			std::lock_guard<std::mutex> lock(mux_);
			if (p_singleton_ == nullptr)//第二次检查:可能两个线程同时通过第一次检查,一个线程获得锁时,可能另外一个线程已经实例化单体
			{
				p_singleton_ = new Singleton();
			}
		}
		return p_singleton_;
	}
private:
	Singleton();
	static Singleton * p_singleton_ ;
	static std::mutex mux_;
};

std::mutex Singleton::mux_;
Singleton * Singleton::p_singleton_ = nullptr;
int main()
{
	auto p1 = Singleton::GetInstance();
	auto p2 = Singleton::GetInstance();
	bool result=( p1 == p2);
	std::cout <<  result << std::endl;

	return 0;
}

其实记住懒汉模式就确保万无一失了,因为当在程序一开始时就调用懒汉模式的GetInstance,就实例化出单例,这等价于饿汉模式。

3、C++11简化版(必看精髓)

但是看起来懒汉模式比较复杂,我们还可以利用C++11对static的改进性质简化代码。

class Singleton
{
public:
	static Singleton* GetInstance()
	{
		static Singleton  singleton;//此变量存在静态区,C++11自带两段检查锁机制来确保static变量实例化一次
		return &singleton;
	}
private:
	Singleton();
};

int main()
{
	auto p1 = Singleton::GetInstance();
	auto p2 = Singleton::GetInstance();
	bool result=( p1 == p2);
	std::cout <<  result << std::endl;

	return 0;
}

这种单例模式的写法可谓是简单地不能再简单了。为什么正确呢?

其实static变量本身全局就只有一份,与单例对象的性质极其相似。而C++11为了确保只初始化static变量一次,提供了两段检查锁机制(在上述代码的汇编代码中,可以清楚地看到两段检查锁的逻辑)。换言之,C++11对于static变量,自带使用了单例模式,自然不用我们再费事。

4、单例模板

在上述代码的基础上改成模板的形式:

#include <iostream>
#include <mutex>
using namespace std;

class A {

};

class B {

};

template <typename T>
class Singleton2 {
public:
	static T * GetInstance() {
		static T t;
		return &t;
	}
protected:
	Singleton2() {}
};

template <typename T>
class Singleton {
public:
	static T * GetInstance() {
		if (pSingle == nullptr) {
			lock_guard<mutex> lock(mtx);
			if (pSingle == nullptr) {
				pSingle = new T();
			}
		}
		return pSingle;
	}
private:
	Singleton() {}
	static T * pSingle;
	static mutex mtx;
};


//mutex Singleton<A>::mtx;
//mutex Singleton<B>::mtx;
//
//A* Singleton<A>::pSingle = nullptr;
//B* Singleton<B>::pSingle = nullptr;
//注释部分代码可以执行,只是每个类都需要单独的两行定义,
//所以使用下面的方法更便捷。
template <typename T>
mutex Singleton<T>::mtx;

template <typename T>
T* Singleton<T>::pSingle = nullptr;

int main() {

	auto pA = Singleton<A>::GetInstance();
	auto pB = Singleton<B>::GetInstance();

	auto pA2 = Singleton<A>::GetInstance();
	auto pB2 = Singleton<B>::GetInstance();

	cout << pA << endl;
	cout << pB << endl;
	cout << pA2 << endl;
	cout << pB2 << endl;

	return 0;
}

但是上述代码有一个问题,类A和B可以直接构造,和单例的语义不太符合。为此,将A和B类的构造函数设定为private,并声明Singleton<T>为相应的友元函数

#include <iostream>
#include <mutex>
using namespace std;

template <typename T>
class Singleton2 {
public:
	static T * GetInstance() {
		static T t;
		return &t;
	}
protected:
	Singleton2() {}
};

template <typename T>
class Singleton {
public:
	static T * GetInstance() {
		if (pSingle == nullptr) {
			lock_guard<mutex> lock(mtx);
			if (pSingle == nullptr) {
				pSingle = new T();
			}
		}
		return pSingle;
	}
private:
	Singleton() {}
	static T * pSingle;
	static mutex mtx;
};

template <typename T>
mutex Singleton<T>::mtx;
template <typename T>
T* Singleton<T>::pSingle = nullptr;

class A {
	friend Singleton<A>;
private:
	A() {}
};

class B {
	friend Singleton<B>;
private:
	B() {}
};


int main() {

	auto pA = Singleton<A>::GetInstance();
	auto pB = Singleton<B>::GetInstance();

	auto pA2 = Singleton<A>::GetInstance();
	auto pB2 = Singleton<B>::GetInstance();

	cout << pA << endl;
	cout << pB << endl;
	cout << pA2 << endl;
	cout << pB2 << endl;

	return 0;
}

 

评论 5
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值