目录
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; }
文章是转载自csdn
https://blog.csdn.net/songchuwang1868/article/details/87882778