懒汉式,使用时再实例化出单例对象
首先重载默认构造函数,拷贝运算符与 = 运算符并设置为私有。因为Singleton不会被实例化,故可不实现默认构造函数
template<typename MotionType>
class Singleton
{
private:
Singleton();
Singleton(const Singleton&) = delete;
Singleton& operator=(const Singleton&) = delete;
};
接着声明pInstance,类型为MotionType* ,GetInstance方法,返回值为MotionType*
private:
static MotionType* pInstance;
public:
static MotionType* GetInstance();
静态成员需要在类外进行初始化
template<class MotionType>
MotionType* Singleton<MotionType>::pInstance = nullptr;
实现获取单例的静态方法,注意new的类型应为MotionType
template<class MotionType>
inline MotionType* Singleton<MotionType>::GetInstance()
{
if (pInstance == nullptr)
pInstance = new MotionType();
return pInstance;
}
整体代码如下,书写在Singleton.hpp中
template<class MotionType>
class Singleton
{
private:
Singleton();
Singleton(const Singleton&) = delete;
Singleton& operator=(const Singleton&) = delete;
static MotionType* pInstance;
public:
static MotionType* GetInstance();
};
template<class MotionType>
MotionType* Singleton<MotionType>::pInstance = nullptr;
template<class MotionType>
inline MotionType* Singleton<MotionType>::GetInstance()
{
if (pInstance == nullptr)
pInstance = new MotionType();
return pInstance;
}
除了Singleton模板类,还应实现GotoCave单例类,GotoCave类同样需要重载默认构造,拷贝构造以及 = 运算符并设置为private。需要注意的是GotoCave类中应将Singleton类设为友元,以让Singleton类能够调用到GotoCave类的构造函数
class GotoCave
{
private:
friend class Singleton<GotoCave>;
GotoCave() {}
GotoCave(const GotoCave&) = delete;
GotoCave& operator=(const GotoCave&) = delete;
public:
//Whatever you want..
};
实际使用中,当模板参数调用到别的头文件中的类时,需要在当前头文件中提前声明,否则编译器将报错 “ xxx:找不到提示 ”
class GotoCave;
//Too many codes..
auto temp = Singleton<GotoCave>::GetInstance();
但是,以上代码存在问题。pInstance作为模板类的成员变量,在程序结束的时候并不会调用GotoCave的析构函数,这样就会导致内存泄漏。在多线程的情况下,某个线程执行new的同时,另一个线程可能正在对if进行判断,而此时实例还未被创建出来,这并不是我们期望的结果。在Effective C++中提到了一种Meyers' Singleton的方法。该方法不仅能防止内存泄漏,还具有线程安全性。改进代码如下
[^Magic Static]: If control enters the declaration concurrently while the variable is being initialized, the concurrent execution shall wait for completion of the initialization. 如果当变量在初始化的时候,并发同时进入声明语句,并发线程将会阻塞等待初始化结束。
template<class MotionType>
class Singleton
{
private:
Singleton();
Singleton(const Singleton&) = delete;
Singleton& operator=(const Singleton&) = delete;
public:
static MotionType& GetInstance();
};
template<class MotionType>
inline MotionType& Singleton<MotionType>::GetInstance()
{
static MotionType Instance;
return Instance;
}
同时,遵循不在头文件以及类中书写函数实现的原则,可在GotoCave.cpp中实现GotoCave类中的构造函数。读者可根据程序需要灵活重载构造函数
//GotoCave.h
class GotoCave
{
private:
friend class Singleton<GotoCave>;
GotoCave();
~GotoCave();
GotoCave(const GotoCave&) = delete;
GotoCave& operator=(const GotoCave&) = delete;
public:
//Whatever you want..
};
//GotoCave.cpp
GotoCave::GotoCave() { //Codes
}
GotoCave::~GotoCave() { //Codes
}
饿汉式,当场直接实例化
实现方法与懒汉式类似
template<class MotionType>
class Singleton
{
private:
Singleton();
Singleton(const Singleton&) = delete;
Singleton& operator=(const Singleton&) = delete;
static MotionType Instance;
public:
static MotionType& GetInstance();
};
template<class MotionType>
MotionType Singleton<MotionType>::Instance;
template<class MotionType>
inline MotionType& Singleton<MotionType>::GetInstance()
{
return Instance;
}
改进的懒汉式单例模板(未完善)
使用智能指针接口,将类包装为线程安全的全局单例类
其中涉及到的知识点有智能指针,单例模板,右值引用,锁以及变参模板
变参模板使之能接受各种单例构造函数,并创建出实例
//SmartSingleton.hpp
#include<memory>
#include<mutex>
template<typename SType>
class SmartSingleton
{
public:
template<typename ...Args>
static std::shared_ptr<SType> GetInstance(Args&&... args)
{
if (!pInstance)
{
std::lock_guard<std::mutex> lg(Mutex);
if (pInstance == nullptr)
//pInstance = std::make_shared<SType>(std::forward<Args>(args)...); //make缺点,调用不到私有的构造函数
pInstance = std::shared_ptr<SType>(new SType(std::forward<Args>(args)...));
}
return pInstance;
}
private:
explicit SmartSingleton();
SmartSingleton(const SmartSingleton&) = delete;
SmartSingleton& operator=(const SmartSingleton&) = delete;
private:
static std::shared_ptr<SType> pInstance;
static std::mutex Mutex;
};
template<typename SType>
std::shared_ptr<SType> SmartSingleton<SType>::pInstance = nullptr;
template<typename SType>
std::mutex SmartSingleton<SType>::Mutex;
测试类
class MyClass
{
friend class SmartSingleton<MyClass>;
private:
MyClass(std::string _name, int _num) : name(_name), num(_num) {}
std::string name;
int num;
public:
~MyClass() { std::cout << "Destory" << std::endl; }
//如果要写析构函数,则应将其设置为public
};
测试代码
int main()
{
auto p = SmartSingleton<MyClass>::GetInstance("Chen", 10);
//Whatever you want with p..
}