📅  最后修改于: 2023-12-03 15:26:03.736000             🧑  作者: Mango
本题涉及如何使用C++编写一个线程安全的单例模式(Singleton Pattern)类。
单例模式是一种设计模式,它保证一个类有且仅有一个实例,并且提供一个全局的访问点。
懒汉式是一种在使用时才会创建实例的单例模式。在懒汉式实现中,需要注意线程安全问题。
class Singleton {
public:
static Singleton& Instance() {
static Singleton instance;
return instance;
}
private:
Singleton() {}; // 构造函数私有化
Singleton(const Singleton&); // 拷贝构造函数私有化
Singleton& operator=(const Singleton&); // 赋值运算符私有化
};
在懒汉式实现中,使用一个静态局部变量来保存单例实例,确保只有在使用时才会创建实例。由于静态局部变量只会在第一次使用时初始化,因此可以保证单例实例只有一个。然而,这种实现方式并不是线程安全的。当多个线程同时访问该类时,在第一个线程创建实例期间,其他线程也会判断出instance为空,然后各自创建实例,导致多个实例的出现。
为了保证线程安全,可以在静态局部变量初始化时加锁。在C++11中,可以用std::call_once来实现这一操作。
#include <mutex>
class Singleton {
public:
static Singleton& Instance() {
std::call_once(once_flag_, &Singleton::init);
return *instance_;
}
private:
Singleton() {};
Singleton(const Singleton&);
Singleton& operator=(const Singleton&);
static void init() {
instance_ = new Singleton();
atexit(destroy);
}
static void destroy() {
if (instance_ != nullptr) {
delete instance_;
instance_ = nullptr;
}
}
static Singleton* instance_;
static std::once_flag once_flag_;
};
在这种实现方式中,once_flag_是std::once_flag类型的全局变量,它保证init函数只会被调用一次。在init函数中,通过new创建对象,并通过atexit在程序结束时自动销毁单例实例(仅适用于单线程环境)。需要注意的是,这种实现方式并没有释放once_flag_和instance_的内存,因此需要在程序结束时手动释放。
饿汉式是一种在程序启动时就创建实例的单例模式。在饿汉式实现中,由于实例是在程序启动时创建的,在使用时不会有线程安全问题。
class Singleton {
public:
static Singleton& Instance() {
return *instance_;
}
private:
Singleton() {};
Singleton(const Singleton&);
Singleton& operator=(const Singleton&);
static Singleton* instance_;
};
Singleton* Singleton::instance_ = new Singleton();
这种实现方式与懒汉式相比较简单,但有一个缺点:由于实例是在程序启动时创建的,对于经常不会用到该实例的程序而言,它是一种资源浪费。