单例模式是指在整个系统生命周期内,保证一个类只能产生一个实例,确保该类的唯一性。
单例类
template <typename T>
class singleton
{
public:
static T& instance()
{
static T instance;
return instance;
}
// 删除声明的实例不能被复制或移动构造,也不能被赋值,从而保证了单例模式的特性:全局唯一性
singleton(T&&) = delete; // 删除移动构造函数,防止通过移动构造函数创建新的对象实例
singleton(const T&) = delete; // 删除拷贝构造函数,防止通过拷贝构造函数创建新的对象实例
void operator=(const T&) = delete; // 删除赋值操作符重载,防止通过赋值操作符赋值给已有的对象实例
protected:
singleton() = default;
virtual ~singleton() = default;
};
-
static T instance;
:在instance()
成员函数中,我们声明了一个静态局部变量instance
。在C++中,静态局部变量在第一次被调用时初始化,并且在程序的整个生命周期中只初始化一次。这就是单例模式的关键所在,确保类的实例只被创建一次。 -
删除拷贝和移动构造函数:通过将拷贝构造函数
singleton(const T&)
和移动构造函数singleton(T&&)
声明为delete
,我们可以阻止通过拷贝或移动创建新的实例。这是为了确保单例对象的唯一性。 -
删除赋值操作符:同样地,
void operator=(const T&) = delete;
删除了赋值操作符,防止已存在的实例被赋值为另一个实例,保持单例的唯一性。 -
保护化构造函数:构造函数
singleton()
被声明为protected
,这意味着不能从类的外部直接创建singleton
对象。这确保了所有实例都必须通过instance()
静态方法创建。 -
虚析构函数:析构函数被声明为
virtual
和default
,这是为了确保如果singleton
类被继承,基类的析构函数会正确调用派生类的析构函数,避免资源泄漏。
注意事项:
- 这个实现没有考虑多线程环境下的安全性。在多线程环境中,
instance()
函数可能会导致多个线程同时初始化instance
,破坏单例特性。要解决这个问题,可以使用双重检查锁定(Double-Checked Locking)或其他线程安全技术。 - 如果
T
类有资源管理需求,可能需要考虑使用智能指针(例如std::unique_ptr
)来代替静态局部变量,以确保资源在程序结束时被正确释放。但是,使用智能指针会引入额外的复杂性和开销,且与单例模式的传统实现不符。
继承这个单例
class entity : public singleton<entity>
{
public:
entity();
~entity();
std::string name;
private:
};
entity::entity()
{
}
entity::~entity()
{
}
类的调用
其它函数中
{
std::string e_name = entity::instance().name;
}