一、什么是单例
单例 Singleton 是设计模式的一种,其特点是只提供唯一一个类的实例,具有全局变量的特点,在任何位置都可以通过接口获取到那个唯一实例;
具体运用场景如:
- 设备管理器,系统中可能有多个设备,但是只有一个设备管理器,用于管理设备驱动;
- 数据池,用来缓存数据的数据结构,数据在全局中只需要一份,单例可避免数据结构多次创建浪费内存;
- 工具类,对一些常用函数进行封装的工具类,在全局中也只需要一份;
- 其他在全局中唯一的对象。
二、单例分类
单例模式可以分为懒汉式(饱汉式)和饿汉式,两者之间的区别在于创建实例的时间点不同:
-
懒汉式(饱汉式):延迟加载,指系统运行中,实例并不存在,只有当需要使用该实例时,才会去创建并使用实例。(这种方式要考虑线程安全)
- 优点:天生线程安全,无需关注线程安全问题。且相比饿汉式第一次调用时效率更高。
- 缺点:在不需要此对象的时候对象已经加载,在某个时间段内占用了不必要的内存。
- 空间换时间
-
饿汉式:立即加载,指系统一运行,就初始化创建实例,当需要时,直接调用即可。(本身就线程安全,没有多线程的问题)
- 优点:在未第一次用到此对象时,对象并不占用空间,节省一定时间段内的内存。
- 缺点:在对象创建时,需要关注线程安全问题。且第一次调用会加载目标对象,耗时需关注。
- 时间换空间
总结:其实你想用啥模式用啥模式,人家单例主打的一个单一实例,重点也不在什么时候加载上,把析构、构造、拷贝构造干掉,保持全局唯一对象即可。况且,你那个对象,十有八九程序刚跑起来就用上了,个人感觉大多情况下两种模式差距很小。
三、单例实现要点
- 构造函数和析构函数为private类型,目的禁止外部构造和析构
- 拷贝构造和赋值构造函数为private类型,目的是禁止外部拷贝和赋值,确保实例的唯一性
- 类里有个获取实例的静态函数,可以全局访问
四、C++单例可继承模版具体实现(懒汉模式)
实现代码
#ifndef __SINGLE_HPP__
#define __SINGLE_HPP__
#include <functional>
#include <mutex>
using std::shared_ptr;
//懒汉式(延迟加载)单例模版
//智能指针无法托管私有构造函数的类(继承类的问题),故自制RAII
template<typename T>
class Single
{
public:
template<typename... Args>
static T* getInstence(Args&&... args)
{
//双检锁,避免每次调用都加锁
if (nullptr == _pInstance)
{
std::lock_guard<std::mutex> lock(_mutex);
if (nullptr == _pInstance)
_pInstance = new T(std::forward<Args>(args)...);
}
return _pInstance;
}
//基类构造函数为protected,保证子类可以继承
protected:
//用于自动销毁 RAII
class AutoRelease
{
public:
AutoRelease() = default;
~AutoRelease()
{
if (nullptr != _pInstance)
delete _pInstance;
}
};
Single() = default;
virtual ~Single() = default;
Single(const Single&) = delete;
Single& operator=(const Single&) = delete;
Single(const Single&&) = delete;
Single& operator=(const Single&&) = delete;
private:
static T* _pInstance;
static AutoRelease _autoRelease;
static std::mutex _mutex;
};
template<typename T>
T* Single<T>::_pInstance = nullptr;
template<typename T>
typename Single<T>::AutoRelease Single<T>::_autoRelease;
template<typename T>
std::mutex Single<T>::_mutex;
//静态内部变量实现方式
template<typename T>
class Singleton {
public:
template<typename... Args>
static T& getInstence(Args&&... args) noexcept(std::is_nothrow_constructible<T>::value) {
static T _pInstance(std::forward<Args>(args)...);
return _pInstance;
}
protected:
Singleton() = default;
virtual ~Singleton() noexcept = default;
Singleton(const Singleton&) = delete;
Singleton& operator =(const Singleton&) = delete;
Singleton(const Singleton&&) = delete;
Singleton& operator =(const Singleton&&) = delete;
};
#endif // !__SINGLE_HPP__
调用实例
//RAII+静态指针变量形式
class MyClass1 : public Single<MyClass1>
{
//父类需为子类友元,以便能够调用子类私有构造、析构函数
friend class Single<MyClass1>;
public:
void test()
{
printf("this is test function\n");
}
private:
MyClass1() = default;
MyClass1(int a) {printf("MyClass1(int a), a = %d\n",a);};
~MyClass1() = default;
};
//静态内部变量形式
class MyClass2 : public Singleton<MyClass2>
{
friend class Singleton<MyClass2>;
public:
void test()
{
printf("this is test function\n");
}
private:
MyClass2() = default;
MyClass2(int a) {printf("MyClass2(int a), a = %d\n",a);};
~MyClass2() = default;
};
int main()
{
MyClass1* cls1 = MyClass1::getInstence(3);
MyClass2& cls2 = MyClass2::getInstence(4);
cls1->test();
cls2.test();
return 0;
}