单例模式指在整个系统生命周期里,保证一个类只能产生一个实例,确保该类的唯一性。
单例模式可以分为懒汉式和饿汉式,两者之间的区别在于创建实例的时间不同:
classSingleton{public:// 外部接口,获取单例对象指针static Singleton*GetInstance();// 释放单例,进程退出时调用staticvoiddeleteInstance();private:// 将其构造和析构成为私有的, 禁止外部构造和析构,后续代码就不再重复添加这块Singleton();~Singleton();// 将其拷贝构造和赋值构造成为私有函数, 禁止外部拷贝和赋值Singleton(const Singleton&signal);const Singleton&operator=(const Singleton&signal);private:// 唯一单例对象指针static Singleton*m_SingleInstance;};//初始化静态成员变量 Singleton*Singleton::m_SingleInstance=NULL; Singleton*Singleton::GetInstance(){if(m_SingleInstance==NULL){ m_SingleInstance=new(std::nothrow) Singleton;// 没有加锁是线程不安全的,当线程并发时会创建多个实例}return m_SingleInstance;}void Singleton::deleteInstance(){if(m_SingleInstance){delete m_SingleInstance; m_SingleInstance=NULL;}}
classSingleton{public:// 获取单实例对象static Singleton*GetInstance();//释放单实例,进程退出时调用staticvoiddeleteInstance();private:// 将其构造和析构成为私有的, 禁止外部构造和析构...private:// 唯一单实例对象指针static Singleton*m_SingleInstance;static std::mutex m_Mutex;// 锁};//初始化静态成员变量 Singleton*Singleton::m_SingleInstance=NULL; std::mutex Singleton::m_Mutex; Singleton* Singleton::GetInstance(){// 这里使用了两个 if判断语句的技术称为双检锁;好处是,只有判断指针为空的时候才加锁,// 避免每次调用 GetInstance的方法都加锁,锁的开销毕竟还是有点大的。if(m_SingleInstance==NULL){ std::unique_lock<std::mutex>lock(m_Mutex);// 加锁if(m_SingleInstance==NULL){ m_SingleInstance=new(std::nothrow) Singleton;}}return m_SingleInstance;}void Singleton::deleteInstance(){ std::unique_lock<std::mutex>lock(m_Mutex);// 加锁,避免释放两次if(m_SingleInstance){delete m_SingleInstance; m_SingleInstance=NULL;}}
classSingleton{public:// 获取单实例对象static Singleton&GetInstance();private:// 禁止外部构造Singleton();// 禁止外部析构~Singleton();// 禁止外部复制构造Singleton(const Single&signal);// 禁止外部赋值操作const Singleton&operator=(const Singleton&Singleton);}; Singleton& Singleton::GetInstance(){// 局部静态特性的方式实现单实例static Singleton signal;return signal;}
classSingleton{public:// 获取单实例static Singleton*GetInstance();// 释放单实例,进程退出时调用staticvoiddeleteInstance();private:// 将其构造和析构成为私有的, 禁止外部构造和析构..private:// 唯一单实例对象指针static Singleton*g_pSingleton;};// 代码一运行就初始化创建实例 ,本身就线程安全 Singleton* Singleton::g_pSingleton=new(std::nothrow) Singleton; Singleton* Singleton::GetInstance(){return g_pSingleton;}void Singleton::deleteInstance(){if(g_pSingleton){delete g_pSingleton; g_pSingleton=NULL;}}
单例模式就像一个被封装在类里面的全局变量,所以全局变量有的缺点它都有:多线程不友好、代码耦合度高、追踪状态变化困难。
但是单例模式的有点还是很明显的,就是访问方便,直接使用全局唯一访问接口就能访问到类。只要包含头文件谁都可以进行访问,没有限制。
便利的访问是使用单例的主要原因,能够让随时随地获取所需的对象
游戏中的许多单例类都是Manager类型功能,通常这些“管理类”的功能就是管理其他对象,或者就是一个工具类,比如专门写日志的。。
当需要管理游戏内一类对象的时候,只需要一个全局Manager类型 的保姆就可以了。
在确定使用单例模式前,需要确定是否类实例化出的对象是否是一定是全局唯一的。
就比如一个游戏中,写日志的类只有一个就可以了,那么就声明一个全局访问写日志的接口。
或者是游戏资源数据的管理,在其他例如窗口类中,如果需要这个资源,那可以直接去访问这个全局接口,而不是说在类里面自己再重新加载一份。
template<typename T>classSingleton{public:static T&GetInstance(){static T instance;return instance;}Singleton(T&&)=delete;Singleton(const T&)=delete;voidoperator=(const T&)=delete;protected:Singleton()=default;virtual~Singleton()=default;};classFoo:public Singleton<Foo>{public:voidoperator()(){ cout<<&GetInstance()<< endl;}};