一、Singleton
确保一个类只有
一个实例
,并提供一个全局访问点
。模式具有创建目的并处理更具动态性
的对象关系。Singleton通常用作另一种设计模式的一部分;
1、优点
能够保证正确的逻辑性,以及良好的效率;
2、适用场景
- 必须有
单一类
的实例,并且客户端必须可以从众所周知的访问点访问它;- 当唯一的实例应该可以通过
子类化
来扩展,并且客户端应该能够在不修改其代码的情况下使用扩展的实例;
3、模板示例
线程非安全版本
class Singleton{
private:
Singleton();
Singleton(const Singleton& other);
public:
static Singleton* getInstance();
static Singleton* m_instance;
};
Singleton* Singleton::m_instance=nullptr;
//线程非安全版本
Singleton* Singleton::getInstance() {
if (m_instance == nullptr) {
m_instance = new Singleton();
}
return m_instance;
}
用于多线程中,会出现线程安全问题;
线程安全版
//线程安全版本,但锁的代价过高
Singleton* Singleton::getInstance() {
Lock lock;
if (m_instance == nullptr) {
m_instance = new Singleton();
}
return m_instance;
}
使用锁,会大大简单性能;
线程安全版双检查锁
//双检查锁,但由于内存读写reorder不安全
Singleton* Singleton::getInstance() {
if(m_instance==nullptr){
Lock lock;
if (m_instance == nullptr) {
m_instance = new Singleton();
}
}
return m_instance;
}
减少锁的覆盖区域,使用双检查锁;但该方法会大概率被编译器优化,导致先没有构建对象的前提下,直接对m_instance赋予地址;
C++11版
//C++ 11版本之后的跨平台实现 (volatile)
std::atomic<Singleton*> Singleton::m_instance;
std::mutex Singleton::m_mutex;
Singleton* Singleton::getInstance() {
Singleton* tmp = m_instance.load(std::memory_order_relaxed);
std::atomic_thread_fence(std::memory_order_acquire);//获取内存fence
if (tmp == nullptr) {
std::lock_guard<std::mutex> lock(m_mutex);
tmp = m_instance.load(std::memory_order_relaxed);
if (tmp == nullptr) {
tmp = new Singleton;
std::atomic_thread_fence(std::memory_order_release);//释放内存fence
m_instance.store(tmp, std::memory_order_relaxed);
}
}
return tmp;
}