【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
分类:
C++_Notes
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 25岁的心里话
· 闲置电脑爆改个人服务器(超详细) #公网映射 #Vmware虚拟网络编辑器
· 零经验选手,Compose 一天开发一款小游戏!
· 因为Apifox不支持离线,我果断选择了Apipost!
· 通过 API 将Deepseek响应流式内容输出到前端