【c++八股】手撕单例模式
懒汉模式
class Singleton {
public:
static Singleton& Instance() {
if(instance_ == nullptr)
instance_ = new Singleton();
}
return instance_;
}
private:
Singleton() {}
~Singleton() {}
// 防拷贝
Singleton(const Singleton& sing) = delete;
Singleton& operator=(const Singleton& sing) = delete;
static Singleton* instance_;
};
Singleton* Singleton::instance_ = nullptr;
懒汉模式-线程安全加锁
假如多个线程都调用了Instance
方法,且都走到了判断为空那一步,可能同时成立。这样会导致多个线程同时创建instance_
对象,即创建了多次,出现线程不安全的情况。
使用lock_guard和mutex进行加锁:
class Singleton {
public:
static Singleton* Instance() {
//不需要每次都进来获取锁资源,提高效率
if(instance_ == nullptr) {
lock_guard<mutex> lk(mutex_);
if(instance_ == nullptr) {
instance_ = new Singleton();
}
}
return instance_;
}
private:
Singleton() {}
~Singleton() {}
Singleton(const Singleton& sing) = delete;
Singleton& operator=(const Singleton& sing) = delete;
static Singleton* instance_;
static mutex mutex_;
};
Singleton* Singleton::instance_ = nullptr;
mutex Singleton::mutex_;
懒汉模式-内存泄漏优化
单例类中new出来的实例没有得到释放,所以需要方法来delete这个对象。
解决方法:(1)智能指针(2)嵌套类(3)C++11的静态对象特性
1 智能指针
利用shared_ptr的特性。
class Singleton {
public:
static boost::shared_ptr<Singleton> Instance() {
if(instance_ == nullptr) {
lock_guard<mutex> lk(mutex_);
if(instance_ == nullptr) {
// 替换托管对象,并设置智能指针引用计数为0后的delete方法
instance_.reset(new Singleton(), destroyInstance);
}
}
return instance_;
}
static void destroyInstance(Singleton* instance) {
delete instance;
}
private:
Singleton() {}
~Singleton() {}
Singleton(const Singleton& sing) = delete;
Singleton& operator=(const Singleton& sing) = delete;
static boost::shared_ptr<Singleton> instance_;
static mutex mutex_;
};
boost::shared_ptr<Singleton> Singleton::instance_ = nullptr;
mutex Singleton::mutex_;
2 嵌套类
在单例类中内嵌一个类,并初始化一个静态对象。当程序结束的时候,该对象进到析构的同时,将单例实例删除。这样就能回收单例实例的资源。
class Singleton {
public:
static Singleton* Instance() {
if(instance_ == nullptr) {
lock_guard<mutex> lk(mutex_);
if(instance == nullptr) {
instance_ = new Singleton();
}
}
return instance_;
}
private:
Singleton() {}
~Singleton() {}
Singleton(const Singleton& sing) = delete;
Singleton& operator=(const Singleton& sing) = delete;
static Deletor deletor_;
static Singleton* instance_;
static mutex mutex_;
class Deletor {
public:
Deletor() {}
~Deletor() {
if(instance_ != nullptr) {
delete instance_;
instance_ = nullptr;
}
}
}
};
Singleton::Deletor Singleton::deletor_;
Singleton* Singleton::instance_ = nullptr;
mutex Singleton::mutex_;
3 C++11的静态对象特性
C++11标准规定局部的静态对象在多线程场景下,只有初次访问才会被创建实例,后续都是直接获取。若未创建成功,其他线程就会等待,不会出现竞争的情况。而且资源会自动被销毁释放。
class Singleton {
public:
static Singleton* Instance() {
static Singleton* instance_;
return instance_;
}
private:
Singleton() {}
~Singleton() {}
Singleton(const Singleton& sing) = delete;
Singleton* operator=(const Singleton& sing) = delete;
};
饿汉模式
程序启动阶段会初始化类的静态变量。
优点是不会有线程安全问题,缺点是浪费内存。
static对象在不同编译单元中的初始化顺序是未定义的。如果在初始化完成之前调用 Instance() 方法会返回一个未定义的实例。
class Singleton {
public:
// 对外提供获取实例的静态方法
static Singleton* Instance() {
return instance_;
}
private:
// 私有构造函数
Singleton() {}
// 防拷贝
Singleton(const Singleton& sing) = delete;
Singleton& operator=(const Singleton& sing) = delete;
static Singleton* instance_;
};
Singleton* Singleton::instance_ = new Singleton();
参考
https://blog.csdn.net/db_linux_driver/article/details/132548669