布吉网站建设wordpress 最近登录

当前位置: 首页 > news >正文

布吉网站建设,wordpress 最近登录,wordpress 店铺推荐,做科研交流常用的网站作者#xff1a;翟天保Steven 版权声明#xff1a;著作权归作者所有#xff0c;商业转载请联系作者获得授权#xff0c;非商业转载请注明出处 一、单例模式是什么#xff1f; 单例模式是一种创建型的软件设计模式#xff0c;在工程项目中非常常见。通过单例模式的设计翟天保Steven 版权声明著作权归作者所有商业转载请联系作者获得授权非商业转载请注明出处 一、单例模式是什么 单例模式是一种创建型的软件设计模式在工程项目中非常常见。通过单例模式的设计使得创建的类在当前进程中只有一个实例并提供一个全局性的访问点这样可以规避因频繁创建对象而导致的内存飙升情况。 实现单例模式的三个要点 1私有化构造函数这样外界就无法自由地创建类对象进而阻止了多个实例的产生。 2类定义中含有该类的唯一静态私有对象静态变量存放在全局存储区且是唯一的供所有对象使用。 3用公有的静态函数来获取该实例提供了访问接口。 单例模式一般分为懒汉式和饿汉式。 1懒汉式在使用类对象单例实例时才会去创建它不然就懒得去搞。 2饿汉式单例实例在类装载时构建有可能全局都没使用过但它占用了空间就像等着发救济粮的饿汉提前排好队等吃的一样。 二、懒汉式实现 2.1 懒汉基础实现 最基本的懒汉实现方法。 //Singleton.h /**************************************************/ #include iostreamusing namespace std;// 单例模式演示类 class Singleton { public:// 公有接口获取唯一实例static Singleton* getInstance(){// 若为空则创建if (instance nullptr) {cout 实例为空开始创建。 endl;instance new Singleton();cout 创建结束。 endl;}else {cout 已有实例返回。 endl;}return instance;} private:// 私有构造函数Singleton(){cout 构造函数启动。 endl;};// 私有析构函数~Singleton(){cout 析构函数启动。 endl;}; private:// 静态私有对象static Singleton* instance; };// 初始化 Singleton* Singleton::instance nullptr; //main.h /************************************************/ #include iostream #include Singleton.husing namespace std;int main() {cout main开始 endl;Singleton* s1 Singleton::getInstance();Singleton* s2 Singleton::getInstance();Singleton* s3 Singleton::getInstance();cout main结束 endl;return 0; } 执行代码让我们看看结果。 从结果中可以看出这样设计主要有两个问题一个是线程安全另一个是内存泄漏。 线程安全是因为在多线程场景下有可能出现多个线程同时进行new操作的情况没通过加锁来限制。 内存泄漏是因为使用了new在堆上分配了资源那么在程序结束时也应该进行delete确保堆中数据释放。 接下来我们先解决线程安全问题对懒汉式实现进行改进。 2.2 基于双重检测锁的懒汉实现 通过双重检测锁可以确保线程安全。 //Singleton.h /************************************************/ #include iostream #include mutexusing namespace std;// 单例模式演示类 class Singleton { public:// 公有接口获取唯一实例static Singleton* getInstance(){// 若为空则创建if (instance nullptr) {// 加锁保证线程安全// 如果两个线程同时进行到这一步一个线程继续向下执行时另一个线程被堵塞// 等锁解除后被堵塞的线程就会跳过下面的if了因为此时实例已经构建完毕lock_guardmutex l(m_mutex);if (instance nullptr) {cout 实例为空开始创建。 endl;instance new Singleton();cout 地址为: instance endl;cout 创建结束。 endl;}}else {cout 已有实例返回。 endl;}return instance;} private:// 私有构造函数Singleton(){cout 构造函数启动。 endl;};// 私有析构函数~Singleton(){cout 析构函数启动。 endl;}; private:// 静态私有对象static Singleton* instance;// 锁static mutex m_mutex; };// 初始化 Singleton* Singleton::instance nullptr; mutex Singleton::m_mutex; //main.h /************************************************/ #include iostream #include Singleton.husing namespace std;int main() {cout main开始 endl;thread t1([] {Singleton* s1 Singleton::getInstance();});thread t2([] {Singleton* s2 Singleton::getInstance();});t1.join();t2.join();Singleton* s3 Singleton::getInstance();cout 地址为: s3 endl;cout main结束 endl;return 0; } 执行代码让我们看看结果。 这样看来没有问题那如果取消双重检测锁在多线程下看看会发生什么。将代码部分函数修改为下。把锁注释掉再查看地址信息。 // 公有接口获取唯一实例 static Singleton* getInstance(){// 若为空则创建if (instance nullptr) {// 加锁保证线程安全// 如果两个线程同时进行到这一步一个线程继续向下执行时另一个线程被堵塞// 等锁解除后被堵塞的线程就会跳过下面的if了因为此时实例已经构建完毕//lock_guardmutex l(m_mutex);if (instance nullptr) {cout 实例为空开始创建。 endl;instance new Singleton();cout 地址为: instance endl;cout 创建结束。 endl;}}else {cout 已有实例返回。 endl;}return instance; } 此时结果中可以看出两个线程进行了两次new操作但是最后只能捕捉到最后一次new的地址信息了前面的那个丢失了。。。。。 这个测试也是让大家直观地感受下双重检测锁的用处。 接下来我们再解决内存泄漏(资源释放)问题对懒汉式实现进行进一步的改进。 2.3 基于双重检测锁和资源管理的懒汉实现 在2.2的基础上我们加入资源管理机制以达到对资源的释放的目的解决方法有两个智能指针静态嵌套类。 2.3.1 智能指针方案 将实例指针更换为智能指针另外智能指针在初始化时还需要人为添加公有的毁灭函数因为析构函数私有化了。 //Singleton.h /************************************************/ #include iostream #include mutexusing namespace std;// 单例模式演示类 class Singleton { public:// 公有接口获取唯一实例static shared_ptrSingleton getInstance(){// 若为空则创建if (instance nullptr) {// 加锁保证线程安全// 如果两个线程同时进行到这一步一个线程继续向下执行时另一个线程被堵塞// 等锁解除后被堵塞的线程就会跳过下面的if了因为此时实例已经构建完毕lock_guardmutex l(m_mutex);if (instance nullptr) {cout 实例为空开始创建。 endl;instance.reset(new Singleton(), destoryInstance);cout 地址为: instance endl;cout 创建结束。 endl;}}else {cout 已有实例返回。 endl;}return instance;}// 毁灭实例static void destoryInstance(Singleton* x) {cout 自定义释放实例 endl;delete x;} private:// 私有构造函数Singleton(){cout 构造函数启动。 endl;};// 私有析构函数~Singleton(){cout 析构函数启动。 endl;}; private:// 静态私有对象static shared_ptrSingleton instance;// 锁static mutex m_mutex; };// 初始化 shared_ptrSingleton Singleton::instance; mutex Singleton::m_mutex; //main.h /***********************************************/ #include iostream #include Singleton.husing namespace std;int main() {cout main开始 endl;thread t1([] {shared_ptrSingleton s1 Singleton::getInstance();});thread t2([] {shared_ptrSingleton s2 Singleton::getInstance();});t1.join();t2.join();shared_ptrSingleton s3 Singleton::getInstance();cout 地址为: s3 endl;cout main结束 endl;return 0; } 应用智能指针后在程序结束时它自动进行资源的释放解决了内存泄漏的问题。 2.3.2 静态嵌套类方案 类中定义一个嵌套类初始化该类的静态对象当程序结束时该对象进行析构的同时将单例实例也删除了。 //Singleton.h /***********************************************/ #include iostream #include mutexusing namespace std;// 单例模式演示类 class Singleton { public:// 公有接口获取唯一实例static Singleton* getInstance() {// 若为空则创建if (instance nullptr) {// 加锁保证线程安全// 如果两个线程同时进行到这一步一个线程继续向下执行时另一个线程被堵塞// 等锁解除后被堵塞的线程就会跳过下面的if了因为此时实例已经构建完毕lock_guardmutex l(m_mutex);if (instance nullptr) {cout 实例为空开始创建。 endl;instance new Singleton();cout 地址为: instance endl;cout 创建结束。 endl;}}else {cout 已有实例返回。 endl;}return instance;} private:// 私有构造函数Singleton() {cout 构造函数启动。 endl;};// 私有析构函数~Singleton() {cout 析构函数启动。 endl;};// 定义一个删除器class Deleter {public:Deleter() {};~Deleter() {if (instance ! nullptr) {cout 删除器启动。 endl;delete instance;instance nullptr;}}};// 删除器是嵌套类,当该静态对象销毁的时候也会将单例实例销毁static Deleter m_deleter; private:// 静态私有对象static Singleton* instance;// 锁static mutex m_mutex; };// 初始化 Singleton* Singleton::instance nullptr; mutex Singleton::m_mutex; Singleton::Deleter Singleton::m_deleter; main.h同2.2中的一致结果如下可以看出当嵌套类Deleter对象销毁时其析构函数执行的实例删除操作也完成了。 2.4 基于局部静态对象的懒汉实现 C11后规定了局部静态对象在多线程场景下的初始化行为只有在首次访问时才会创建实例后续不再创建而是获取。若未创建成功其他的线程在进行到这步时会自动等待。注意C11前的版本不是这样的。 因为有上述的改动所以出现了一种更简洁方便优雅的实现方法基于局部静态对象实现。 //Singleton.h /***********************************************/ #include iostream #include mutexusing namespace std;// 单例模式演示类 class Singleton { public:// 公有接口获取唯一实例static Singleton getInstance() {cout 获取实例 endl;static Singleton instance;cout 地址为: instance endl;return instance;} private:// 私有构造函数Singleton() {cout 构造函数启动。 endl;};// 私有析构函数~Singleton() {cout 析构函数启动。 endl;}; };//main.h /**********************************************/ #include iostream #include Singleton.husing namespace std;int main() {cout main开始 endl;thread t1([] {Singleton s1 Singleton::getInstance();});thread t2([] {Singleton s2 Singleton::getInstance();});t1.join();t2.join();cout main结束 endl;return 0; } 从结果中可以看出构造函数启动了一次另一个线程直接获取了地址。并且当程序结束时进行了自动释放。 三、饿汉式实现 3.1 饿汉基础实现 饿汉和懒汉的差别就在于饿汉提前进行了创建所以它的基础实现也不是很复杂如下所示。 //Singleton.h /***********************************************/ #include iostream #include mutexusing namespace std;// 单例模式演示类 class Singleton { public:// 公有接口获取唯一实例static Singleton* getInstance() {cout 获取实例 endl;cout 地址为: instance endl;return instance;} private:// 私有构造函数Singleton() {cout 构造函数启动。 endl;};// 私有析构函数~Singleton() {cout 析构函数启动。 endl;}; private:// 静态私有对象static Singleton* instance; };// 初始化 Singleton* Singleton::instance new Singleton(); //main.h /************************************************/ #include iostream #include Singleton.husing namespace std;int main() {cout main开始 endl;thread t1([] {Singleton* s1 Singleton::getInstance();});thread t2([] {Singleton* s2 Singleton::getInstance();});t1.join();t2.join();cout main结束 endl;return 0; } 输出结果中可知main还没开始实例就已经构建完毕获取实例的函数也不需要进行判空操作因此也就不用双重检测锁来保证线程安全了它本身已经是线程安全状态了。 但是内存泄漏的问题还是要解决的这点同懒汉是一样的。 3.2 基于资源管理的饿汉实现 内存泄漏解决方法有两个智能指针静态嵌套类。 3.2.1 智能指针方案 将实例指针更换为智能指针另外智能指针在初始化时还需要人为添加公有的毁灭函数因为析构函数私有化了。 //Singleton.h /************************************************/ #include iostream #include mutexusing namespace std;// 单例模式演示类 class Singleton { public:// 公有接口获取唯一实例static shared_ptrSingleton getInstance() {cout 获取实例 endl;cout 地址为: instance endl;return instance;}// 毁灭实例static void destoryInstance(Singleton* x) {cout 自定义释放实例 endl;delete x;} private:// 私有构造函数Singleton() {cout 构造函数启动。 endl;};// 私有析构函数~Singleton() {cout 析构函数启动。 endl;}; private:// 静态私有对象static shared_ptrSingleton instance; };// 初始化 shared_ptrSingleton Singleton::instance(new Singleton(), destoryInstance); //main.h /***********************************************/ #include iostream #include Singleton.husing namespace std;int main() {cout main开始 endl;thread t1([] {shared_ptrSingleton s1 Singleton::getInstance();});thread t2([] {shared_ptrSingleton s2 Singleton::getInstance();});t1.join();t2.join();cout main结束 endl;return 0; } 加入了智能指针后不出意外地进行了自动的资源释放。 3.2.2 静态嵌套类方案 类中定义一个嵌套类初始化该类的静态对象当程序结束时该对象进行析构的同时将单例实例也删除了。 //Singleton.h /***********************************************/ #include iostream #include mutexusing namespace std;// 单例模式演示类 class Singleton { public:// 公有接口获取唯一实例static Singleton* getInstance() {cout 获取实例 endl;cout 地址为: instance endl;return instance;} private:// 私有构造函数Singleton() {cout 构造函数启动。 endl;};// 私有析构函数~Singleton() {cout 析构函数启动。 endl;};// 定义一个删除器class Deleter {public:Deleter() {};~Deleter() {if (instance ! nullptr) {cout 删除器启动。 endl;delete instance;instance nullptr;}}};// 删除器是嵌套类,当该静态对象销毁的时候也会将单例实例销毁static Deleter m_deleter; private:// 静态私有对象static Singleton* instance; };// 初始化 Singleton* Singleton::instance new Singleton(); Singleton::Deleter Singleton::m_deleter; //main.h /*************************************************/ #include iostream #include Singleton.husing namespace std;int main() {cout main开始 endl;thread t1([] {Singleton s1 Singleton::getInstance();});thread t2([] {Singleton* s2 Singleton::getInstance();});t1.join();t2.join();cout main结束 endl;return 0; } 同懒汉的一样不多做阐述。 四、总结 上述讲了这么多关于单例模式的内容我尽可能地将测试的结果也同步展示了目的就是帮助大家更好地理解。文中所有的代码都是完整的可以直接复制到自己的项目中测试验证下。 最后如果说让我选择用什么样的实现那我选择用局部静态对象的方法代码简洁线程安全内存无泄漏有什么理由说不呢除非你是C11之前的版本。。。。 如果文章帮助到你了可以点个赞让我知道我会很快乐~加油