单例设计模式
单例模式是一种常用的软件设计模式,其目标是确保一个类只有一个实例,并提供一个全局访问点。在C++中,可以通过以下步骤实现单例模式:
- 私有化构造函数,以防止外界创建单例类的对象。
- 使用类的私有静态指针变量指向类的唯一实例。
- 使用一个公有的静态方法获取该实例。
以下是一个简单的C++单例模式的实现示例:
class Singleton
{
private:
static Singleton* instance;
Singleton() {}
~Singleton() {}
Singleton(const Singleton&);
Singleton& operator=(const Singleton&);
public:
static Singleton* getInstance()
{
if (instance == NULL)
instance = new Singleton();
return instance;
}
};
// Initialize static member
Singleton* Singleton::instance = NULL;
这个例子中,Singleton
类的构造函数是私有的,这意味着不能从类的外部创建Singleton
对象。唯一的Singleton
实例是通过getInstance()
函数创建的,该函数检查instance
是否为NULL
,如果是,则创建一个新的Singleton
对象1。
然而,这个简单的实现在多线程环境下可能会有问题。如果两个线程同时调用getInstance()
,可能会创建两个Singleton
实例。为了解决这个问题,可以使用双检查锁定模式(Double-Checked Locking Pattern)1。
此外,C++11引入了内存模型,提供了原子操作来实现内存的同步访问,因此在C++11后可以正确地跨平台实现双检查锁定模式1。
请注意,这只是单例模式的一种实现方式,还有其他的实现方式,例如懒汉式、饿汉式等2。具体选择哪种实现方式取决于你的具体需求和环境。在选择合适的实现方式时,你需要考虑多线程安全、资源管理、程序的性能和复杂性等因素2。
在C++中,双重检查锁定模式(Double-Checked Locking Pattern,DCLP)也被用于实现单例模式的“惰性初始化”。这种模式在某些语言在某些硬件平台的实现可能是不安全的。有的时候,这一模式被看做是反模式1。
以下是一个C++中使用双重检查锁定模式的例子1:
std::mutex mlock;
class Singleton {
private:
Singleton() {}
static Singleton * ptr;
public:
static Singleton * Create() {
if (ptr == nullptr) { // 第一次检查
std::lock_guard<std::mutex> lock(mlock); // 获取锁
if (ptr == nullptr) { // 第二次检查
ptr = new Singleton();
}
}
return ptr;
}
};
Singleton * Singleton::ptr = nullptr;
在这个例子中,Singleton::Create()
方法首先检查ptr
是否为nullptr
(第一次检查)。如果ptr
为nullptr
,则获取锁并再次检查ptr
是否为nullptr
(第二次检查)。只有在ptr
为nullptr
的情况下,才会创建新的Singleton
实例。这样,除了初始化的时候会加锁,后续的调用都是直接返回,解决了多余的性能消耗2。
需要注意的是,这种模式在多线程环境中可能会有问题,因为C++的内存模型允许“无序写入”,有些编译器因为性能原因,可能会把上述步骤中的 2 和 3 进行重排序2。为了解决这个问题,可以使用volatile
关键字,但是使用volatile
关键字的代码也不能保证正常工作在多线程环境中1。具体原因分析请参考"C++ and the Perils of Double-Checked Locking"这篇论文1。
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 分享4款.NET开源、免费、实用的商城系统
· 全程不用写代码,我用AI程序员写了一个飞机大战
· MongoDB 8.0这个新功能碉堡了,比商业数据库还牛
· 白话解读 Dapr 1.15:你的「微服务管家」又秀新绝活了
· 上周热点回顾(2.24-3.2)