单例模式顾名思义,保证一个类仅可以有一个实例化对象,并且提供一个可以访问它的全局接口。实现单例模式必须注意一下几点:
-
单例类只能由一个实例化对象。
-
单例类必须自己提供一个实例化对象。
-
单例类必须提供一个可以访问唯一实例化对象的接口。
单例模式分为懒汉和饿汉两种实现方式。
懒汉单例模式
懒汉:故名思义,不到万不得已就不会去实例化类,也就是说在第一次用到类实例的时候才会去实例化一个对象。在访问量较小,甚至可能不会去访问的情况下,采用懒汉实现,这是以时间换空间。
(1)非线程安全的懒汉单例模式
/* * 关键代码:构造函数是私有的,不能通过赋值运算,拷贝构造等方式实例化对象。 */ //懒汉式一般实现:非线程安全,getInstance返回的实例指针需要delete class Singleton { public: static Singleton* getInstance(); ~Singleton(){} private: Singleton(){} //构造函数私有 Singleton(const Singleton& obj) = delete; //明确拒绝 Singleton& operator=(const Singleton& obj) = delete; //明确拒绝 static Singleton* m_pSingleton; }; Singleton* Singleton::m_pSingleton = NULL; Singleton* Singleton::getInstance() { if(m_pSingleton == NULL) { m_pSingleton = new Singleton; } return m_pSingleton; }
(2)线程安全的懒汉单例模式
std::mutex mt; class Singleton { public: static Singleton* getInstance(); private: Singleton(){} //构造函数私有 Singleton(const Singleton&) = delete; //明确拒绝 Singleton& operator=(const Singleton&) = delete; //明确拒绝 static Singleton* m_pSingleton; }; Singleton* Singleton::m_pSingleton = NULL; Singleton* Singleton::getInstance() { if(m_pSingleton == NULL) { mt.lock(); if(m_pSingleton == NULL) { m_pSingleton = new Singleton(); } mt.unlock(); } return m_pSingleton; }
饿汉单例模式
饿汉:饿了肯定要饥不择食。所以在单例类定义的时候就进行实例化。在访问量比较大,或者可能访问的线程比较多时,采用饿汉实现,可以实现更好的性能。这是以空间换时间。
//饿汉式:线程安全,注意一定要在合适的地方去delete它 class Singleton { public: static Singleton* getInstance(); private: Singleton(){} //构造函数私有 Singleton(const Singleton&) = delete; //明确拒绝 Singleton& operator=(const Singleton&) = delete; //明确拒绝 static Singleton* m_pSingleton; }; Singleton* Singleton::m_pSingleton = new Singleton(); Singleton* Singleton::getInstance() { return m_pSingleton; }