一、概念
单例 Singleton 是设计模式的一种,其特点是只提供唯一一个类的实例,具有全局变量的特点,在任何位置都可以通过接口Instance() 获取到那个唯一实例。
二、使用场景
当代码中需要唯一一个实例存在的类的全局变量的时候才使用单例,比如管理器之类的。
三、如何才能写一个单例
- static 保证只有一个实例;
- 构造函数的访问方式设为private 避免用户自己实例化类;
- Singleton(Singleton&)=delete 禁止拷贝;
- Singleton& operator=(const Singleton&)=delete 禁止赋值;
- 用户通过接口Instance() 获取实例 使用 static 类成员函数;
四、如何才能写一个好单例
尽可能小;尽可能简单;保证线程安全;内存不泄露;
五、最推荐的懒汉式单例—局部静态变量
- 通过局部静态变量的特性保证了线程安全 (C++11, GCC > 4.3, VS2015支持该特性);
- 注意在使用的时候需要声明单例的引用
Single&
才能获取对象。
#include <iostream>
class Singleton
{
public:
~Singleton(){
std::cout<<"destructor called!"<<std::endl;
}
Singleton(const Singleton&)=delete;
Singleton& operator=(const Singleton&)=delete;
static Singleton& get_instance(){
static Singleton instance;
return instance;
}
private:
Singleton(){
std::cout<<"constructor called!"<<std::endl;
}
};
int main(int argc, char *argv[])
{
Singleton& instance_1 = Singleton::get_instance();
Singleton& instance_2 = Singleton::get_instance();
return 0;
}
这种方法又叫做 Meyers' SingletonMeyer's的单例, 是著名的写出《Effective C++》系列书籍的作者 Meyers 提出的。所用到的特性是在C++11标准中的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<typename T>
class Singleton{
public:
static T& instance(){
//初始化Manager,调用Manager的构造函数,同时调用Singleton的构造函数
static T _instance;
return _instance;
}
protected:
virtual ~Singleton(){std::cout<<u8"~Singleton()..."<<std::endl;}
//protected修饰的构造函数才能被别人继承
Singleton(){std::cout<<u8"Singleton()..."<<std::endl;}
Singleton(const Singleton&)=delete;
Singleton& operator=(const Singleton&)=delete;
};
class Manager: public Singleton<Manager>{
// friend能让Singleton<T>访问到Manager的构造函数
friend class Singleton<Manager>;
private:
Manager(){std::cout<<u8"Manager()..."<<std::endl;}
~Manager(){std::cout<<u8"~Manager()..."<<std::endl;}
Manager(const Manager&)=delete;
Manager& operator=(const Manager&)=delete;
};
int main()
{
Manager& singleton = Manager::instance();
Manager& singleton2 = Manager::instance();
return 0;
}
//输出
//Singleton()...
//Manager()...
//~Manager()...
//~Singleton()...