设计模式系列--单例模式
设计模式系列--单例模式
提示
设计模式一般分为23种,当前系列的语言全部采用c++实现
问题:写一个单例模式?
基本的单例模式写法
当看到这个问题时,是否有一种这问题怎么这么简单的想法,立即提笔(摸上键盘)随手就写出来一个:
class Singleton{
public:
Singleton() = default;
~Singleton() = default;
static Singleton* intance(){
static Singleton instance;
return &instance;
}
}
显然,这是最容易写出来的一种单例写法,这种写法在大部分情况下能够满足要求,但是这种写法也存在一些问题,比如:
- 没有线程安全(不过从c++11开始static 已经支持线程安全了)
such a variable is initialized the first time control passes through its declaration; such a variable is considered initialized upon the completion of its initialization. If the initialization exits by throwing an exception, the initialization is not complete, so it will be tried again the next time control enters the declaration. If control enters the declaration concurrently while the variable is being initialized, the concurrent execution shall wait for completion of the initialization. If control re-enters the declaration recursively while the variable is being initialized, the behavior is undefined.
- 无法实现范型,如果有多个类都要访问单例的话,每个类都要实现instance()函数
以下就逐步的来解决上述问题。
实例指针写法(懒汉式)
在c++11之前,static并不是线程安全的,因此如果想在单例里面实现线程安全,需要自己加锁保证。如果项目中是c++11标准(目前基本所有的编译器都支持了c++标准),则可以跳过这个章节,当然如果不确定是否支持static线程安全,也可以用这种写法
需要用一个static指针来存储创建的单例实例,可以写下如下代码:
#include <mutex>
class Singleton{
public:
Singleton() = default;
~Singleton() = default;
static Singleton* instance(){
std::lock_guard lock(m_mutex);
if(instance_ == nullptr){
instance_ = new Singleton();
}
return instance_;
}
protected:
static std::mutex m_mutex;
static Singleton* instance_;
};
Singleton* Singleton::instance_ = nullptr;
优化写法
上面的写法有个问题,每次调用instance()时都要加一次锁,比较耗时,所以应该加一次判断,再使用懒汉式访问
#include <mutex>
class Singleton{
public:
Singleton() = default;
~Singleton() = default;
static Singleton* instance(){
if(instance_ == nullptr){
std::lock_guard lock(m_mutex);
if(instance_ == nullptr){
instance_ = new Singleton();
}
}
return instance_;
}
protected:
static std::mutex m_mutex;
static Singleton* instance_;
};
Singleton* Singleton::instance_ = nullptr;
这样在访问instance时,如果instance_已经创建了,将不会调用锁,在频繁调用场景下可以大幅提高访问性能
范型写法
基于以上优化写法,要使Singleton通用,则使用范型来实现:
#include <mutex>
template<class T>
class Singleton{
public:
Singleton() = default;
virtual ~Singleton() = default;
static T* instance(){
if(instance_ == nullptr){
std::lock_guard lock(m_mutex);
if(instance_ == nullptr){
instance_ = new T();
}
}
return instance_;
}
protected:
static std::mutex m_mutex;
static T* instance_;
};
template<class T>
T* Singleton<T>::instance_ = nullptr;
======================================
使用就较为简单了
class Foo : public Singleton<Foo>{
// balabala
}
以上是单例模式的全部讲解,如果疑问、建议或者错误,欢迎评论指正。