参考:https://www.cnblogs.com/gccbuaa/p/7268313.html
参考:https://blog.youkuaiyun.com/fchyang/article/details/81449580
单例模式是应用最多的一种设计模式,它要求每个类有且只能有一个实例对象,所以用C++设计一个单例模式的方法如下:
1 构造函数声明为私有,这样就保证了不能随意构造一个对象。
2 将拷贝构造函数与赋值构造函数声明为私有,并不提供他们的实现; 即禁止对象被拷贝。
3 在类中声明一个静态的全局访问接口;
4 声明一个静态的私有实例化指针;
#单例模式可变参数实现:保证类有且只有一个实例,并提供一个静态的全局访问接口
#pragma once
template<typename T>
class Singleton
{
public:
template<typename...Args> //可变参数
static T* CreateInstance(Args&&... args)
{
if (m_pInstance == nullptr)
{
m_pInstance = new T(std::forward<Args>(args)...);
}
assert( m_pInstance != nullptr );
return m_pInstance;
}
static T* GetInstance( void )
{
if (m_pInstance == nullptr)
{
throw std::logic_error("the instance is not init,please initialize the instance first.");
}
return m_pInstance;
}
static void DestoryInstance()
{
if (m_pInstance != nullptr)
{
delete m_pInstance;
m_pInstance = nullptr;
}
}
private:
Singleton(); //构造函数设置为私有,保证不能随意构造一个对象
virtual ~Singleton(); //不能随意使用释放对象
Singleton(const Singleton&); //拷贝构造函数和赋值构造函数设置为私有,并不提供实现,即禁止对象拷贝
Singleton& operator = (const Singleton&);
static T* m_pInstance; //引用性声明
};
template<class T> T* Singleton<T>::m_pInstance = nullptr; //模板定义性声明
使用方法如下:
#include <iostream>
#include "singleton.hpp"
class Student
{
public:
Student(int boy = 0, int girl = 0);
~Student(void);
int Sum(void) { return girl_ + boy_; }
private:
int boy_;
int girl_;
};
Student::Student(int boy, int girl)
: boy_(boy)
, girl_(girl)
{
}
Student::~Student(void)
{
}
int main()
{
Singleton<Student>::CreateInstance(2,5);
Student* pSt = nullptr;
pSt = Singleton<Student>::GetInstance();
if ( !pSt )
{
std::cout << "create singleton student is failed" << '\n';
return -1;
}
std::cout << pSt->Sum() << '\n';
getchar();
Singleton<Student>::DestoryInstance();
return 0;
}
注意:此单例模式只使用于单线程创建实例, 如果想在多线程中使用, 需要在CreateInstace()、GetInstance()和DestroyInstance()加入锁
上面就是一种单例类模式的C++实现,但是上述代码还有一个缺点:单例类中申请的一些资源需要手动回收,不太方便。下面提供的处理方式显然要比上面方式来的要便捷,因为它依靠内部提供的Garbo嵌套类来提供服务,当Singleton类生命周期结束时,Garbo的类对象garbo_也要销毁,它将调用析构函数,而在析构函数中又自动地释放了Singleton单例类申请的一些资源,这种实现就比较智能化。不需要手动释放资源。这是它的优势。如下所示:
template<typename T>
class Singleton
{
public:
template<typename...Args> //可变参数
static T* CreateInstance(Args&&... args)
{
if (m_pInstance == nullptr)
{
m_pInstance = new T(std::forward<Args>(args)...);
}
assert( m_pInstance != nullptr );
return m_pInstance;
}
static T* GetInstance( void )
{
if (m_pInstance == nullptr)
{
throw std::logic_error("the instance is not init,please initialize the instance first.");
}
return m_pInstance;
}
public:
class Garbo //资源回收机制
{
public:
~Garbo()
{
if( Singleton::m_pInstance != nullptr )
{
delete m_pInstance;
m_pInstance = nullptr;
}
}
};
private:
Singleton(); //构造函数设置为私有,保证不能随意构造一个对象
virtual ~Singleton(); //不能随意使用释放对象
Singleton(const Singleton&); //拷贝构造函数和赋值构造函数设置为私有,并不提供实现,即禁止对象拷贝
Singleton& operator = (const Singleton&);
static T* m_pInstance; //引用性声明
static Garbo m_garbo; //利用对象的确定性析构
};
template<class T> T* Singleton<T>::m_pInstance = nullptr; //模板定义性声明
template<class T> T* Singleton<T>::Garbo Singleton::m_garbo; //定义性声明
int main()
{
Singleton<Student>::CreateInstance(2,5);
Student* pSt = nullptr;
pSt = Singleton<Student>::GetInstance();
if ( !pSt )
{
std::cout << "create singleton student is failed" << '\n';
return -1;
}
std::cout << pSt->Sum() << '\n';
getchar();
return 0;
}
下面提供另一种实现C++单例类模式的方法:声明一个局部静态对象(不是线程安全)
class Singleton
{
public:
static Singleton* GetInstance();
void Init();
protected:
Singleton();
~Singleton();
public:
int m_classID;
std::vector<float> m_fConf;
private:
Singleton(const Singleton &other);
Singleton & operator=(const Singleton &other);
static Singleton* m_instance; // 局部静态对象
};
Singleton* Singleton::m_instance = nullptr;
Singleton* Singleton::GetInstance()
{
if ( m_instance = nullptr )
{
static Singleton ms_Singleton;
m_instance = &ms_Singleton;
}
return m_instance;
}
Singleton::Singleton():m_classID(0), m_fConf(std::vector<float>())
{
cout << "Singleton "<<endl;
}
Singleton::~Singleton()
{
cout << "释放内存资源"<<endl;
if ( m_instance != nullptr )
{
delete m_instance;
m_instance = nullptr;
}
}
这种实现方式利用了static修改函数内部的变量,当第一次调用GetInstance函数时,系统将构造一个Singleton静态对象,在后续再次调用这个函数时,系统不再执行这个语句,也就不会再构造Singleton类对象了,而直接返回m_instance本身。另外,当Singleton类对象生命周期结束时,对象会自动调用析构函数销毁,这里也就可以不用担心释放问题,需要注意的是构造函数、拷贝构造函数和赋值构造函数均私有化。
int main()
{
Singleton* s1 = Singleton::GetInstance();
Singleton* s2 = Singleton::GetInstance(); //s1与s2是同一对象的指针
return 0;
}