为什么需要单例模式?
所谓“单例模式”,指的就是一个类只能有一个或者几个实例化的对象——比如说,在 Windows 或者 macOS 这样的桌面操作系统里,鼠标指针箭头有且只有一个,不能出现第二个。
**
懒汉与饿汉
单例分为两种实现方法:
- 懒汉
第一次用到类实例的时候才会去实例化
- 饿汉
单例类定义的时候就进行了实例化
懒汉模式代码:
class singleton {
private:
singleton(){}
static singleton *p;
public:
static singleton *instance();
};
singleton *singleton::p =nullptr;
singleton* singleton::instance(){
if(p ==nullptr)
p =new singleton();
return p;
}
饿汉模式代码:(**自己写代码首选这种**)
因为是定义就进行了实例化,所以会造成资源浪费
#include <iostream>
class singleton {
private:
singleton(){
std::cout << "饿汉模式构造函数" << std::endl;
}
static singleton *p;
public:
static singleton *instance(){
return p;
}
void print(){
std::cout << "you did it!" << std::endl;
}
};
singleton *singleton::p = new singleton();
int main()
{
singleton *pp = singleton::instance();
pp->print();
return 0;
}
注: l懒汉模式只适合在单线程下,当多线程时,是不安全的。考虑两个线程同时首次调用instance方法且同时检测到p是nullptr,则两个线程会同时构造一个实例给p,这将违反了单例的准则。**
最终版本 (懒汉模式线程优化)
C++11下的单例模式
mutex singleton::lock_;
atomic<singleton *> singleton::p;
/*
* std::atomic_thread_fence(std::memory_order_acquire);
* std::atomic_thread_fence(std::memory_order_release);
* 这两句话可以保证他们之间的语句不会发生乱序执行。
*/
singleton *singleton::instance(){
singleton *tmp = p.load(memory_order_relaxed);
atomic_thread_fence(memory_order_acquire);
if(tmp ==nullptr){
lock_guard<mutex> guard(lock_);
tmp = p.load(memory_order_relaxed);
if(tmp ==nullptr){
tmp =new singleton();
atomic_thread_fence(memory_order_release);
p.store(tmp, memory_order_relaxed);
}
}
return p;
}
如果是在unix平台的话,除了使用atomic operation外,在不适用C++11的情况下,还可以通过pthread_once来实现Singleton。
class singleton {
private:
singleton();//私有构造函数,不允许使用者自己生成对象
singleton(const singleton &other);
//要写成静态方法的原因:类成员函数隐含传递this指针(第一个参数)
staticvoid init(){
p =new singleton();
}
staticpthread_once_t ponce_;
static singleton *p;//静态成员变量
public:
singleton *instance(){
// init函数只会执行一次
pthread_once(&ponce_,&singleton::init);
return p;
}
};
参考:
https://www.bookstack.cn/read/CPlusPlusThings/68fdd6c8536795e6.md