网站建设定制开发服务,深圳网站建设 案例,推广计划表格,wordpress更改后台文章目录 25. 单例模式25.1. 饿汉式单例模式25.2. 懒汉式单例模式25.2.1. 解决方案125.2.2. 解决方案2 #xff08;推荐写法#xff09; 运行在VS2022#xff0c;x86#xff0c;Debug下。 25. 单例模式 单例即该类只能有一个实例。 应用#xff1a;如在游戏开发中#x… 文章目录 25. 单例模式25.1. 饿汉式单例模式25.2. 懒汉式单例模式25.2.1. 解决方案125.2.2. 解决方案2 推荐写法 运行在VS2022x86Debug下。 25. 单例模式 单例即该类只能有一个实例。 应用如在游戏开发中可以使用单例模式来管理各种资源确保这些资源在整个游戏中只被加载和管理一次。 实现 将构造函数和析构函数私有不允许外部构造或析构类对象。将拷贝构造函数、赋值运算符、移动构造函数和移动赋值运算符删除不允许复制类对象。需要有一个静态函数接口返回唯一的静态实例。 分类 饿汉式单例模式在main()开始前实例就已经存在了。懒汉式单例模式在第一次调用获取实例时才创建实例。
25.1. 饿汉式单例模式
代码如下。
class Singleton
{
private:Singleton() {} //私有构造函数~Singleton() {} //私有析构函数Singleton(const Singleton) delete; //删除拷贝构造函数Singleton operator(const Singleton) delete; //删除赋值运算符Singleton(Singleton) delete; //删除移动构造函数Singleton operator(Singleton) delete; //删除移动赋值运算符private:static Singleton instance; //静态成员变量存储实例public:static Singleton* getInstance() //静态成员函数获取实例{return instance;}
};Singleton Singleton::instance; //静态成员变量实例化int main()
{Singleton* s1 Singleton::getInstance();Singleton* s2 Singleton::getInstance();return 0;
}在main()处设置断点监视窗口如下实例的内存地址为0x00E0C138。 总结 优点线程安全因为程序运行时就已经生成唯一的实例。缺点不是按需创建实例。
25.2. 懒汉式单例模式
新增一个静态函数接口用于释放实例内存。代码如下。
class Singleton
{
private:Singleton(){} //私有构造函数~Singleton(){} //私有析构函数Singleton(const Singleton) delete; //删除拷贝构造函数Singleton operator(const Singleton) delete; //删除赋值运算符Singleton(Singleton) delete; //删除移动构造函数Singleton operator(Singleton) delete; //删除移动赋值运算符private:static Singleton* instance; //静态成员变量存储实例public:static Singleton* getInstance() //静态成员函数获取实例{if (instance nullptr)instance new Singleton();return instance;}static void deleteInstance() //静态成员函数释放实例{if (instance ! nullptr){delete instance;instance nullptr;}}
};Singleton* Singleton::instance nullptr; //静态成员变量定义和初始化int main()
{Singleton* s1 Singleton::getInstance();Singleton* s2 Singleton::getInstance();Singleton::deleteInstance();return 0;
}在main()处设置断点监视窗口如下此时未生成实例。 第一次调用getInstance()获取实例时生成实例实例的内存地址为0x00E16A08。 总结 优点按需创建实例。缺点 不是线程安全如两个线程同时调用getInstance()获取实例同时运行到判断instance是否为nullptr的if语句并且instance并未创建那么两个线程都会创建一个实例。内存释放问题在程序执行结束时调用deleteInstance()释放实例内存但是要确保delete之后没有代码再调用getInstance()或者访问已释放的内存存在安全隐患。
25.2.1. 解决方案1
针对线程安全问题加锁。针对内存释放问题对于全局变量或静态变量main()返回后会调用析构函数。基于此可以定义一个静态成员变量用于释放实例内存。代码如下。
mutex m;class Singleton
{
private:Singleton() {} //私有构造函数~Singleton() {} //私有析构函数Singleton(const Singleton) delete; //删除拷贝构造函数Singleton operator(const Singleton) delete; //删除赋值运算符Singleton(Singleton) delete; //删除移动构造函数Singleton operator(Singleton) delete; //删除移动赋值运算符static Singleton* instance; //静态成员变量存储实例class Garbo //在析构函数中释放实例{public:~Garbo(){if (Singleton::instance ! nullptr){delete instance;instance nullptr;}}};static Garbo garbo; //静态成员变量在程序执行结束时系统会调用它的析构函数public:static Singleton* getInstance() //静态成员函数获取实例{if (instance nullptr) //加锁前判断这样如果实例存在就不需加锁了{lock_guardmutexlock(m); //创建实例前加锁if (instance nullptr)instance new Singleton();}return instance;}
};Singleton* Singleton::instance nullptr; //静态成员变量定义和初始化int main()
{Singleton* s1 Singleton::getInstance();Singleton* s2 Singleton::getInstance();return 0;
}25.2.2. 解决方案2 推荐写法
在静态函数接口里定义局部静态变量存储实例。那么它会在第一次调用获取实例时才创建可以按需创建实例。同时内部__Init_thread_header()和_Init_thread_footer()可以保证局部静态变量的初始化是线程安全的。代码如下。
class Singleton
{
private:Singleton() {} //私有构造函数~Singleton() {} //私有析构函数Singleton(const Singleton) delete; //删除拷贝构造函数Singleton operator(const Singleton) delete; //删除赋值运算符Singleton(Singleton) delete; //删除移动构造函数Singleton operator(Singleton) delete; //删除移动赋值运算符public:static Singleton* getInstance() //静态成员函数获取实例{static Singleton instance; //局部静态成员变量存储实例return instance;}
};int main()
{Singleton* s1 Singleton::getInstance();Singleton* s2 Singleton::getInstance();return 0;
}反汇编分析如下。