单例模式保证一个类仅有一个实例,并提供一个访问它的全局访问点。

        C++11之前,实现一个通用的泛型单例模式时,会遇到一个问题这个泛型单例能够创建所有的类型对象,但是这些类型构造函数形参可能尽不相同参数个数参数类型可能都不相同,这导致我们不容易做一个所有类型都通用的单例。一种方法通过定义一些创建单例模板函数实现。在一般情况下,类型构造函数形参不超过6个,所以可以通过定义0~6个形参创建单例的模板函数实现一个通用的单例模式代码如下所示

#include <iostream>
using namespace std;

template<typename T>
class Singleton
{
public:
	///支持0个参数构造函数
	static T* Instance()
	{
		if (m_pInstance == nullptr)
		{
			m_pInstance = new T();
		}
		return m_pInstance;
	}

	///支持1个参数构造函数
	template<typename T0>
	static T* Instance(T0 arg0)
	{
		if (m_pInstance == nullptr)
		{
			m_pInstance = new T(arg0);
		}
		return m_pInstance;
	}

	///支持2个参数构造函数
	template<typename T0, typename T1&gt;
	static T* Instance(T0 arg0, T1 arg1)
	{
		if (m_pInstance == nullptr)
		{
			m_pInstance = new T(arg0, arg1);
		}
		return m_pInstance;
	}

	///支持3个参数构造函数
	template<typename T0, typename T1, typename T2&gt;
	static T* Instance(T0 arg0, T1 arg1, T2 arg2)
	{
		if (m_pInstance == nullptr)
		{
			m_pInstance = new T(arg0, arg1, arg2);
		}
		return m_pInstance;
	}

	///支持4个参数的构造函数
	template<typename T0, typename T1, typename T2, typename T3&gt;
	static T* Instance(T0 arg0, T1 arg1, T2 arg2, T3 arg3)
	{
		if (m_pInstance == nullptr)
		{
			m_pInstance = new T(arg0, arg1, arg2, arg3);
		}
		return m_pInstance;
	}

	///支持5个参数的构造函数
	template<typename T0, typename T1, typename T2, typename T3, typename T4>
	static T* Instance(T0 arg0, T1 arg1, T2 arg2, T3 arg3, T4 arg4)
	{
		if (m_pInstance == nullptr)
		{
			m_pInstance = new T(arg0, arg1, arg2, arg3, arg4);
		}
		return m_pInstance;
	}

	///支持6个参数的构造函数
	template<typename T0, typename T1, typename T2, typename T3, typename T4, typename T5>
	static T* Instance(T0 arg0, T1 arg1, T2 arg2, T3 arg3, T4 arg4, T5 arg5)
	{
		if (m_pInstance == nullptr)
		{
			m_pInstance = new T(arg0, arg1, arg2, arg3, arg4, arg5);
		}
		return m_pInstance;
	}

	///获取单例
	static T* GetInstance()
	{
		if (m_pInstance == nullptr)
		{
			std::logic_error("the instance is not init, please initialize the instance first");
		}

		return m_pInstance;
	}

	///释放单例
	static void DestoryInstance()
	{
		delete m_pInstance;

		m_pInstance = nullptr;
	}

private:
	///不允许复制赋值
	Singleton(void);
	virtual ~Singleton(void);
	Singleton(const Singleton&amp;);
	Singleton&amp; operator=(const Singleton&amp;);

private:
	static T* m_pInstance;
};

template<class T> 
T* Singleton<T>::m_pInstance = nullptr;

class A
{
public:
	A()
	{
		cout << "construct A...." << endl;
	}
};

class B 
{
public:
	B(int x)
	{
		m_x = x;
		cout << "construct B...." << endl;
	}
private:
	int m_x;
};

class C 
{
public:
	C(int x, double db)
	{
		m_x = x;
		m_db = db;
		cout << "construct C...." << endl;
	}
private:
	int m_x;
	int m_db;
};


int main()
{
	///创建A类型的单例
	Singleton<A>::Instance();

	///创建B类型的单例
	Singleton<B>::Instance(1);

	///创建C类型的单例
	Singleton<C>::Instance(1, 2.0);


	Singleton<A>::DestoryInstance();
	Singleton<B>::DestoryInstance();
	Singleton<C>::DestoryInstance();


	return 0;
}

        从测试代码可以看到这个Singleton<T>可以创建部分类型,支持不超过6个参数的类型。不过,从实现代码可以看到,有很多重复的模板定义,这种定义繁琐而又重复,当参数超过6个时,我们不得不再增加模板定义。这种预先定义足够多的模板函数的方法显得重复又不够灵活。

        C++11d可变数模板正好可以消除这种重复,同时支持完美转发,即避免不必要的内存复制高性能,又增加了灵活性。C++11实现的一个简洁通用的单例模式如下所示

#include <iostream>
#include <string>
#include <thread>
#include <mutex>
#include <string.h>
using namespace std;


template<typename T>
class Singleton
{
public:
	template<typename ...Args>
	static T* Instance(Args&amp;&amp; ...args)
	{
		if (m_pInstance == nullptr) 
		{
			///完美转发
			m_pInstance = new T(std::forward<Args>(args)...);
		}

		return m_pInstance;
	}

	///获取单例
	static T* GetInstance()
	{
		if (m_pInstance == nullptr)
		{
			throw std::logic_error("the instance is not init, please initialize the instance first");
		}

		return m_pInstance;
	}

	static void DestoryInstance()
	{
		delete m_pInstance ;
		m_pInstance = nullptr;
	}

private:
	Singleton(void);
	virtual ~Singleton();
	Singleton(const Singleton&amp;);
	Singleton&amp; operator=(const Singleton&amp;);

private:
	static T* m_pInstance;
};

template<class T>
T* Singleton<T>::m_pInstance = nullptr;


class A
{
public:
	A(const string&amp; )
	{
		cout << "A lvalue" << endl;
	}

	A(string&& )
	{
		cout << "A rvalue" << endl;
	}
};

class B 
{
public:
	B(const string& )
	{
		cout << "B lvalue" << endl;
	}

	B(string&& )
	{
		cout << "B rvalue" << endl;
	}
};

class C
{
public:
	C(int x, int y)
	{
		cout << "C construct" << endl;
	}

	void func()
	{
		cout << "class C call func..." << endl;
	}
};

std::once_flag init_flagA;
std::once_flag init_flagB;
std::once_flag init_flagC;

void func1()
{
	///为了保证在多线程环境中某个函数仅被调用一次比如需要初始化某个对象,而这个对象只能初始化一次,就可以用std::call_once来保证在多线程环境中只被调用一次
	std::call_once(init_flagA, []() {Singleton<A>::Instance("123");});

	std::call_once(init_flagB, []() {Singleton<B>::Instance(std::move("abc"));});

	std::call_once(init_flagC, []() {Singleton<C>::Instance(1, 2);});
}

void func2()
{
	///为了保证在多线程环境中某个函数仅被调用一次比如需要初始化某个对象,而这个对象只能初始一次,就可以用std::call_once来保证在多线程环境中只被调用一次
	std::call_once(init_flagA, []() {Singleton<A>::Instance("456");});

	std::call_once(init_flagB, []() {Singleton<B>::Instance(std::move("efg"));});

	std::call_once(init_flagC, []() {Singleton<C>::Instance(3, 4);});
}

int main()
{
	thread t1(func1);
	thread t2(func1);

	t1.join();
	t2.join();

	Singleton<C>::GetInstance()->func();

	getchar();

	Singleton<A>::DestoryInstance();

	Singleton<B>::DestoryInstance();

	Singleton<C>::DestoryInstance();

	return 0;
}

        可以看到,C++11版本的通用单例模式实现没有重复的模板定义,支持任意个数参数的类型创建,不用再担心模板函数定义得不够,还支持完美转发,无论是左值还是右值都能转发到正确的构造函数中通过右值引用移动语义还能进一步高性能简洁而优雅。

原文地址:https://blog.csdn.net/qq_25048473/article/details/134775374

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任

如若转载,请注明出处:http://www.7code.cn/show_41646.html

如若内容造成侵权/违法违规/事实不符,请联系代码007邮箱suwngjj01@126.com进行投诉反馈,一经查实,立即删除

发表回复

您的电子邮箱地址不会被公开。 必填项已用 * 标注