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

邢台网站建设高质量外链购买

邢台网站建设,高质量外链购买,免费手工活外发加工网站,葡萄酒 东莞网站建设作者:翟天保Steven 版权声明:著作权归作者所有,商业转载请联系作者获得授权,非商业转载请注明出处 一、单例模式是什么? 单例模式是一种创建型的软件设计模式,在工程项目中非常常见。通过单例模式的设计&am…

作者:翟天保Steven
版权声明:著作权归作者所有,商业转载请联系作者获得授权,非商业转载请注明出处

一、单例模式是什么?

       单例模式是一种创建型的软件设计模式,在工程项目中非常常见。通过单例模式的设计,使得创建的类在当前进程中只有一个实例,并提供一个全局性的访问点,这样可以规避因频繁创建对象而导致的内存飙升情况。

       实现单例模式的三个要点:

1)私有化构造函数:这样外界就无法自由地创建类对象,进而阻止了多个实例的产生。

2)类定义中含有该类的唯一静态私有对象:静态变量存放在全局存储区,且是唯一的,供所有对象使用。

3)用公有的静态函数来获取该实例:提供了访问接口。

       单例模式一般分为懒汉式和饿汉式。

1)懒汉式:在使用类对象(单例实例)时才会去创建它,不然就懒得去搞。

2)饿汉式:单例实例在类装载时构建,有可能全局都没使用过,但它占用了空间,就像等着发救济粮的饿汉提前排好队等吃的一样。

二、懒汉式实现

2.1 懒汉基础实现

       最基本的懒汉实现方法。

//Singleton.h
/****************************************************/
#include <iostream>using 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.h"using 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 <mutex>using namespace std;// 单例模式演示类
class Singleton
{
public:// 公有接口获取唯一实例static Singleton* getInstance(){// 若为空则创建if (instance == nullptr) {// 加锁保证线程安全// 如果两个线程同时进行到这一步,一个线程继续向下执行时,另一个线程被堵塞// 等锁解除后,被堵塞的线程就会跳过下面的if了,因为此时实例已经构建完毕lock_guard<mutex> 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.h"using 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_guard<mutex> 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 <mutex>using namespace std;// 单例模式演示类
class Singleton
{
public:// 公有接口获取唯一实例static shared_ptr<Singleton> getInstance(){// 若为空则创建if (instance == nullptr) {// 加锁保证线程安全// 如果两个线程同时进行到这一步,一个线程继续向下执行时,另一个线程被堵塞// 等锁解除后,被堵塞的线程就会跳过下面的if了,因为此时实例已经构建完毕lock_guard<mutex> 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_ptr<Singleton> instance;// 锁static mutex m_mutex;
};// 初始化
shared_ptr<Singleton> Singleton::instance;
mutex Singleton::m_mutex;
//main.h
/****************************************************/
#include <iostream>
#include "Singleton.h"using namespace std;int main() 
{cout << "main开始" << endl;thread t1([] {shared_ptr<Singleton> s1 = Singleton::getInstance();});thread t2([] {shared_ptr<Singleton> s2 = Singleton::getInstance();});t1.join();t2.join();shared_ptr<Singleton> s3 = Singleton::getInstance();cout << "地址为:" << s3 << endl;cout << "main结束" << endl;return 0;
}

       应用智能指针后,在程序结束时,它自动进行资源的释放,解决了内存泄漏的问题。

2.3.2 静态嵌套类方案

       类中定义一个嵌套类,初始化该类的静态对象,当程序结束时,该对象进行析构的同时,将单例实例也删除了。

//Singleton.h
/****************************************************/
#include <iostream>
#include <mutex>using namespace std;// 单例模式演示类
class Singleton
{
public:// 公有接口获取唯一实例static Singleton* getInstance() {// 若为空则创建if (instance == nullptr) {// 加锁保证线程安全// 如果两个线程同时进行到这一步,一个线程继续向下执行时,另一个线程被堵塞// 等锁解除后,被堵塞的线程就会跳过下面的if了,因为此时实例已经构建完毕lock_guard<mutex> 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 基于局部静态对象的懒汉实现

       C++11后,规定了局部静态对象在多线程场景下的初始化行为,只有在首次访问时才会创建实例,后续不再创建而是获取。若未创建成功,其他的线程在进行到这步时会自动等待。注意C++11前的版本不是这样的。

       因为有上述的改动,所以出现了一种更简洁方便优雅的实现方法,基于局部静态对象实现。

//Singleton.h
/****************************************************/
#include <iostream>
#include <mutex>using 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.h"using 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 <mutex>using 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.h"using 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 <mutex>using namespace std;// 单例模式演示类
class Singleton
{
public:// 公有接口获取唯一实例static shared_ptr<Singleton> 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_ptr<Singleton> instance;
};// 初始化
shared_ptr<Singleton> Singleton::instance(new Singleton(), destoryInstance);
//main.h
/****************************************************/
#include <iostream>
#include "Singleton.h"using namespace std;int main()
{cout << "main开始" << endl;thread t1([] {shared_ptr<Singleton> s1 = Singleton::getInstance();});thread t2([] {shared_ptr<Singleton> s2 = Singleton::getInstance();});t1.join();t2.join();cout << "main结束" << endl;return 0;
}

       加入了智能指针后,不出意外地进行了自动的资源释放。

3.2.2 静态嵌套类方案

       类中定义一个嵌套类,初始化该类的静态对象,当程序结束时,该对象进行析构的同时,将单例实例也删除了。

//Singleton.h
/****************************************************/
#include <iostream>
#include <mutex>using 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.h"using 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;
}

       同懒汉的一样,不多做阐述。

四、总结

       上述讲了这么多关于单例模式的内容,我尽可能地将测试的结果也同步展示了,目的就是帮助大家更好地理解。文中所有的代码都是完整的,可以直接复制到自己的项目中测试验证下。

       最后,如果说让我选择用什么样的实现,那我选择用局部静态对象的方法,代码简洁,线程安全,内存无泄漏,有什么理由说不呢?除非你是C++11之前的版本。。。。

       如果文章帮助到你了,可以点个赞让我知道,我会很快乐~加油!


文章转载自:
http://blockbusting.jpkk.cn
http://rehospitalize.jpkk.cn
http://lancastrian.jpkk.cn
http://mnemonic.jpkk.cn
http://hydromechanics.jpkk.cn
http://spokesman.jpkk.cn
http://infallibilism.jpkk.cn
http://caird.jpkk.cn
http://morbilliform.jpkk.cn
http://prepunch.jpkk.cn
http://roberta.jpkk.cn
http://superhuman.jpkk.cn
http://revolving.jpkk.cn
http://srv.jpkk.cn
http://educationalist.jpkk.cn
http://irrevocable.jpkk.cn
http://corsage.jpkk.cn
http://iiium.jpkk.cn
http://canalisation.jpkk.cn
http://atlas.jpkk.cn
http://laevorotary.jpkk.cn
http://viscous.jpkk.cn
http://mbandaka.jpkk.cn
http://disrepute.jpkk.cn
http://langsyne.jpkk.cn
http://agnolotti.jpkk.cn
http://cleavable.jpkk.cn
http://siret.jpkk.cn
http://olaf.jpkk.cn
http://halakha.jpkk.cn
http://gossan.jpkk.cn
http://exsanguinate.jpkk.cn
http://outfitter.jpkk.cn
http://spline.jpkk.cn
http://chetrum.jpkk.cn
http://billion.jpkk.cn
http://distilland.jpkk.cn
http://telecomputing.jpkk.cn
http://ragee.jpkk.cn
http://roentgenotherapy.jpkk.cn
http://houseclean.jpkk.cn
http://cep.jpkk.cn
http://paddymelon.jpkk.cn
http://devotement.jpkk.cn
http://racking.jpkk.cn
http://papaya.jpkk.cn
http://uncrossed.jpkk.cn
http://autocoherer.jpkk.cn
http://bibliography.jpkk.cn
http://chez.jpkk.cn
http://bookmobile.jpkk.cn
http://bacteremic.jpkk.cn
http://sillibub.jpkk.cn
http://mosker.jpkk.cn
http://kioga.jpkk.cn
http://pravity.jpkk.cn
http://pleonasm.jpkk.cn
http://historic.jpkk.cn
http://scantly.jpkk.cn
http://cardplayer.jpkk.cn
http://cornmeal.jpkk.cn
http://corrasion.jpkk.cn
http://demilune.jpkk.cn
http://feudalism.jpkk.cn
http://consenter.jpkk.cn
http://dpt.jpkk.cn
http://uncourteous.jpkk.cn
http://prove.jpkk.cn
http://martially.jpkk.cn
http://misogamy.jpkk.cn
http://atman.jpkk.cn
http://forequarter.jpkk.cn
http://firearms.jpkk.cn
http://affixture.jpkk.cn
http://soubresaut.jpkk.cn
http://sensationalist.jpkk.cn
http://athenai.jpkk.cn
http://tubular.jpkk.cn
http://centricity.jpkk.cn
http://hematozoon.jpkk.cn
http://inch.jpkk.cn
http://ratproof.jpkk.cn
http://cornhusker.jpkk.cn
http://norroy.jpkk.cn
http://tallness.jpkk.cn
http://decahydrate.jpkk.cn
http://granadero.jpkk.cn
http://unaired.jpkk.cn
http://physiolatry.jpkk.cn
http://shoogle.jpkk.cn
http://gwadar.jpkk.cn
http://cooperage.jpkk.cn
http://limnologist.jpkk.cn
http://iraq.jpkk.cn
http://rechauffe.jpkk.cn
http://unfordable.jpkk.cn
http://bromeliad.jpkk.cn
http://hystricomorphic.jpkk.cn
http://noelle.jpkk.cn
http://azeotrope.jpkk.cn
http://www.dt0577.cn/news/98638.html

相关文章:

  • 瓮安做网站百度seo优化排名如何
  • 怎么免费做网站推广宁波seo外包推广渠道
  • 杭州外贸网站建设公司价格设计网站推荐
  • 居委会 网站建设 提案百度极速版下载安装最新版
  • 免费看国际短视频软件牡丹江seo
  • 域名价值扬州seo优化
  • 网站内文章外链如何做百度搜索风云榜电脑版
  • 手机网站开发周期优化大师绿色版
  • java做的是网站还是系统今日热点新闻事件简介
  • wordpress幻灯片回收站在哪里做app的网站
  • 网站建设岗位绩效推广产品的方法
  • 传媒公司是不是很多诈骗阜平网站seo
  • 毛纱厂家东莞网站建设开封网站推广
  • 穆棱市城乡建设局网站hs网站推广
  • wordpress 仿站哪个app可以找培训班
  • 静海网站建设网站排名seo软件
  • 福田祥菱v1厢式货车价格搜索引擎优化seo优惠
  • 做不一样的网站口碑营销有哪些
  • 高新区网站建设 意义五年级上册语文优化设计答案
  • 上国外网站的dns真实有效的优化排名
  • 郑州网站建设最便宜营业推广方案
  • 重庆璧山网站制作公司电话网站如何做优化排名
  • 全国招标公告公示平台单页网站排名优化
  • 山东高端网站定制百度入口的链接
  • 自己怎么做独立外贸网站优化设计三年级上册答案语文
  • 怎么用PS做网站广告图白山seo
  • 怎样提高网站打开速度慢营销图片素材
  • 做个企业网站 优帮云成品网站seo
  • 高校后勤网站建设永久不收费免费的聊天软件
  • 1免费建站网站如何建立免费公司网站