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

用php做高中数学题库网站找文网客服联系方式

用php做高中数学题库网站,找文网客服联系方式,招聘网站怎么投自己做的简历,如何学习网站建设目录 0. 前言 1. 懒汉式单例模式 1.1 最简单的单例模式 1.2 防止内存泄漏 1.2.1 智能指针的方法 1.2.2 静态嵌套的方法 1.3 保证线程安全 1.4 C11版本的优雅解决方案 2. 饿汉式单例模式 0. 前言 起因是在程序中重复声明了一个单例模式的变量,后来程序怎么调…

目录

0. 前言

1. 懒汉式单例模式

1.1 最简单的单例模式

1.2 防止内存泄漏

1.2.1 智能指针的方法

1.2.2 静态嵌套的方法

1.3 保证线程安全

1.4 C++11版本的优雅解决方案

2. 饿汉式单例模式


0. 前言

起因是在程序中重复声明了一个单例模式的变量,后来程序怎么调都不对,最后发现变量是用单例模式,修改是全局的,所以决定好好梳理一下单例模式。

首先,为什么要用单例模式,就是因为我们希望一个类只有唯一一个实例,并且提供一个全局的访问点。从这个描述不难看出,这个实例应该是要static来修饰的。实际情况中,比如我们想申请一个内存池,程序都用这一块内存池,那么就可以单例模式来实现

1. 懒汉式单例模式

1.1 最简单的单例模式

先来看看最简单的单例模式怎么写,然后分析一下有什么问题。

#include <iostream>
using namespace std;// 最简单的单例模式
class Singleton{
public:// 获取实例的接口static Singleton* getInstance() {if (instance == nullptr) {instance = new Singleton(); // 使用new来创建一个新的实例对象} else {cout << "重复创建,返回已创建的实例。" << endl;}return instance;}
private:// 静态私有对象static Singleton* instance;// 构造函数一定要私有,外部无法直接访问构造函数Singleton() {cout << "运行构造函数" << endl;};~Singleton() {cout << "运行析构函数" << endl;};
};
// 要在类外进行初始化!!!
Singleton* Singleton::instance = nullptr;int main(){Singleton* s1 = Singleton::getInstance();Singleton* s2 = Singleton::getInstance();return 0;
}

这里有两个点需要特别的注意:

  • 单例模式的类需要有一个静态私有的对象,是这个类的实例,且必须在类外进行初始化。
  • 获取实例的接口getInstance()函数式可以被访问和调用的,但是必须返回static类型的变量,实际上就是返回这个类的唯一实例
  • 补充下析构函数私有化的原因:保证只能在堆上new一个新的类对象。因为C++是一个静态绑定的语言。在编译过程中,所有的非虚函数调用都必须分析完成,即使是虚函数也需检查可访问性。当在栈上生成对象时,对象会自动析构,也就说析构函数必须可以访问。而堆上生成对象,由于析构时机由程序员控制,所以不一定需要析构函数。

按照上面的写法,基本上满足了单例模式的初衷,要一个只有一个实例的类。但是存在两个问题,一个是因为使用到了new进行创建,就需要人为进行delete的释放操作,否则就会造成内存泄漏。第二个是程序乍一看只会创建一块内存空间,但是如果考虑多线程,那么就有可能多个线程分别创建了多块内存空间的实例,与我们设计单例模式的初衷相违背。

1.2 防止内存泄漏

1.2.1 智能指针的方法

运行1.1的程序,结果为:

运行构造函数
重复创建,返回已创建的实例。

可以发现,并没有调用析构函数。这里,补充一下析构函数的作用:释放对象的使用资源,并销毁对象的非static数据成员。而我们定义的instance成员变量static的,所以无法直接使用析构函数进行释放。虽然事例的简单程序在运行完之后static变量会自动释放,但是在很多复杂的程序中,使用完instance却不释放是非常致命的会导致内存泄漏的问题。这里采用智能指针的方法,并借用智能指针的reset函数,定义一个销毁的成员函数,通过这个成员函数调用delete来释放我们创建的new内存,达到析构的目的。看看下面的实现。

#include <iostream>
#include <memory>
using namespace std;class Singleton{
public:// 公有接口获取唯一实例static shared_ptr<Singleton> getInstance() {if (instance == nullptr) {instance.reset(new Singleton(), destoryInstance);}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;
};// 初始化
shared_ptr<Singleton> Singleton::instance;int main(){shared_ptr<Singleton> s1 = Singleton::getInstance();shared_ptr<Singleton> s2 = Singleton::getInstance();return 0;
}

运行结果为:

运行构造函数。
重复创建,返回异创建的实例。
自定义释放实例
运行析构函数。

可以看到,我们通过智能指针,在使用完instance资源后调用了自定义的释放函数,即delete了new出来的空间,达到了运行析构函数的目的,防止了内存泄漏。

1.2.2 静态嵌套的方法

解决内存的泄漏的方法,总之是要把释放的过程先写好,不能靠用户每次自己释放。对于本次分享的例子,就是要把delete放进代码里。除了利用智能指针的释放函数来调用delete之外,也可以显式的调用delete函数,要单独嵌套一个类,把这个delete函数放进嵌套类的公有析构函数中。实现过程如下:

#include <iostream>
using namespace std;
class Singleton{
public:// 公有接口获取唯一实例static Singleton* getInstance() {if (instance == nullptr) {if (instance == nullptr) {instance = new Singleton();}}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 deleter; // 删除器也是静态成员变量
private:// 静态私有对象static Singleton* instance;
};// 初始化
Singleton* Singleton::instance = nullptr;
Singleton::Deleter Singleton::deleter;int main()
{Singleton* s1 = Singleton::getInstance();Singleton* s2 = Singleton::getInstance();return 0;
}

运行结果为:

运行构造函数。
重复创建,返回已创建的实例。
删除器启动。
运行析构函数。

1.3 保证线程安全

首先修改一下1.1中的程序,主要是增加一些打印,然后用多个线程创建Singleton的实例,看看是否每个线程都是访问的同一个内存地址。

#include <iostream>
#include <thread>
using namespace std;class Singleton{
public:// 获取实例的接口static Singleton* getInstance() {if (instance == nullptr) {instance = new Singleton(); // 使用new来创建一个新的实例对象cout << "创建地址为:" << instance << endl;} else {cout << "重复创建,返回已创建的实例。" << endl;}return instance;}
private:// 静态私有对象static Singleton* instance;// 构造函数一定要私有,外部无法直接访问构造函数Singleton() {cout << "运行构造函数" << endl;};~Singleton() {cout << "运行析构函数" << endl;};
};
// 要在类外进行初始化!!!
Singleton* Singleton::instance = nullptr;int main(){// Singleton* s1 = Singleton::getInstance();// Singleton* s2 = Singleton::getInstance();thread t1([] {Singleton* s1 = Singleton::getInstance();});thread t2([] {Singleton* s2 = Singleton::getInstance();});t1.join();t2.join();return 0;
}

运行结果如下:

运行构造函数
创建地址为:0x7f0988000b60
运行构造函数
创建地址为:0x7f0980000b60

可以发现,两个线程分别new出了一段内存空间(有一定几率是同一段,会报重复创建)。显然,这违背了我们单例模式的初衷。

解决方法是进行加锁,让一个线程先执行完,另一个线程才能获得new的权限。代码如下:

#include <iostream>
#include <mutex>
#include <thread>
using namespace std;class Singleton{
public:static Singleton* getInstance() {if (instance == nullptr) {lock_guard<mutex> l(mutex1); // 加锁保证线程安全if (instance == nullptr) {instance = new Singleton();cout << "创建地址为:" << instance << endl;}}else {cout << "重复创建,返回已创建的实例。" << endl;}return instance;}
private:static mutex mutex1;// 锁static Singleton* instance;Singleton() {cout << "运行构造函数" << endl;};~Singleton() {cout << "运行析构函数" << endl;};
};// 初始化
Singleton* Singleton::instance = nullptr;
mutex Singleton::mutex1;int main(){thread t1([](){Singleton* s1 = Singleton::getInstance();});thread t2([](){Singleton* s2 = Singleton::getInstance();});t1.join();t2.join();return 0;
}

运行结果为:

运行构造函数
创建地址为:0x7f90d4000b60
重复创建,返回已创建的实例。

加锁后,即使是多个线程,也只会申请一块内存空间。

1.4 C++11版本的优雅解决方案

上面只是为了将这个问题表述清楚,在C++11中,static变量是可以保证线程安全的,同时直接用static变量而不用new,就可以获得线程安全的且无内存泄漏的优雅写法,如下:

#include <iostream>
#include <thread>
using namespace std;
class Singleton{
public:// 公有接口获取唯一实例static Singleton* getInstance() {static Singleton instance;cout << "地址为:" << &instance << endl;return &instance;}private:Singleton() {cout << "运行构造函数" << endl;};~Singleton() {cout << "运行析构函数" << endl;};
};int main()
{thread t1([] {Singleton* s1 = Singleton::getInstance();});thread t2([] {Singleton* s2 = Singleton::getInstance();});t1.join();t2.join();return 0;
}

运行结果如下:

运行构造函数
地址为:0x55b7df269152
地址为:0x55b7df269152
运行析构函数

可以看到访问的内存地址一样,析构函数也正常的运行了。


2. 饿汉式单例模式

饿汉式和懒汉式的差别是,饿汉式提前进行了创建,而如果提前创建static变量,那么在程序开始前这个变量就创建好了,因此不存在线程不安全的问题,只需要保证不内存泄漏即可。用智能指针的方式实现代码如下:

#include <iostream>
#include <thread>
using namespace std;
class Singleton{
public:// 公有接口获取唯一实例static shared_ptr<Singleton> getInstance() {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);int main(){thread t1([] {shared_ptr<Singleton> s1 = Singleton::getInstance();});thread t2([] {shared_ptr<Singleton> s2 = Singleton::getInstance();});t1.join();t2.join();return 0;
}

运行结果为:

运行构造函数。
地址为:0x55977895ceb0
地址为:0x55977895ceb0
自定义释放实例
运行析构函数。

也可以考虑优雅的写法:

#include <iostream>
#include <thread>
using namespace std;
class Singleton{
public:// 公有接口获取唯一实例static Singleton* getInstance() {static Singleton instance;cout << "地址为:" << &instance << endl;return &instance;}private:// 私有构造函数Singleton() {cout << "运行构造函数。" << endl;};// 私有析构函数~Singleton() {cout << "运行析构函数。" << endl;};
};int main(){thread t1([] {Singleton* s1 = Singleton::getInstance();});thread t2([] {Singleton* s2 = Singleton::getInstance();});t1.join();t2.join();return 0;
}

输出的结果为:

运行构造函数。
地址为:0x55aa7a895152
地址为:0x55aa7a895152
运行析构函数。


文章转载自:
http://solanaceous.qkxt.cn
http://pongid.qkxt.cn
http://garibaldino.qkxt.cn
http://bile.qkxt.cn
http://inflection.qkxt.cn
http://spinsterhood.qkxt.cn
http://eteocles.qkxt.cn
http://callipygian.qkxt.cn
http://theme.qkxt.cn
http://fairlead.qkxt.cn
http://loftily.qkxt.cn
http://limation.qkxt.cn
http://mullein.qkxt.cn
http://mauger.qkxt.cn
http://plastosome.qkxt.cn
http://puddling.qkxt.cn
http://unreasonably.qkxt.cn
http://acoustics.qkxt.cn
http://telegraphone.qkxt.cn
http://kinsmanship.qkxt.cn
http://quiet.qkxt.cn
http://poleward.qkxt.cn
http://conciliarism.qkxt.cn
http://niggard.qkxt.cn
http://neighborhood.qkxt.cn
http://zymoid.qkxt.cn
http://lamella.qkxt.cn
http://infinite.qkxt.cn
http://nonstriker.qkxt.cn
http://scab.qkxt.cn
http://polythene.qkxt.cn
http://kinetic.qkxt.cn
http://ennoble.qkxt.cn
http://underpan.qkxt.cn
http://abjective.qkxt.cn
http://tsetse.qkxt.cn
http://gospeler.qkxt.cn
http://voltairean.qkxt.cn
http://thoracectomy.qkxt.cn
http://dlp.qkxt.cn
http://panegyrize.qkxt.cn
http://tremble.qkxt.cn
http://reignite.qkxt.cn
http://lumphead.qkxt.cn
http://silicate.qkxt.cn
http://enervate.qkxt.cn
http://scold.qkxt.cn
http://ibidine.qkxt.cn
http://vibrogram.qkxt.cn
http://crofter.qkxt.cn
http://tactometer.qkxt.cn
http://xanthosiderite.qkxt.cn
http://anachorism.qkxt.cn
http://untrodden.qkxt.cn
http://inequivalve.qkxt.cn
http://gazebo.qkxt.cn
http://xeme.qkxt.cn
http://khrushchev.qkxt.cn
http://portrayal.qkxt.cn
http://warta.qkxt.cn
http://enduringly.qkxt.cn
http://desiccated.qkxt.cn
http://up.qkxt.cn
http://medal.qkxt.cn
http://sanguivorous.qkxt.cn
http://brava.qkxt.cn
http://skiwear.qkxt.cn
http://towhead.qkxt.cn
http://misdescribe.qkxt.cn
http://practicability.qkxt.cn
http://incept.qkxt.cn
http://bathable.qkxt.cn
http://hebraist.qkxt.cn
http://partner.qkxt.cn
http://teleferique.qkxt.cn
http://implantable.qkxt.cn
http://zine.qkxt.cn
http://bathochrome.qkxt.cn
http://farina.qkxt.cn
http://hieroglyphist.qkxt.cn
http://can.qkxt.cn
http://locusta.qkxt.cn
http://druggy.qkxt.cn
http://salerno.qkxt.cn
http://blithe.qkxt.cn
http://monophase.qkxt.cn
http://bacterium.qkxt.cn
http://intransit.qkxt.cn
http://feller.qkxt.cn
http://strictly.qkxt.cn
http://pantler.qkxt.cn
http://canvass.qkxt.cn
http://highbred.qkxt.cn
http://ultraradical.qkxt.cn
http://siberian.qkxt.cn
http://saba.qkxt.cn
http://chancellor.qkxt.cn
http://unillusioned.qkxt.cn
http://putresce.qkxt.cn
http://clinch.qkxt.cn
http://www.dt0577.cn/news/59087.html

相关文章:

  • 哪个网站做h5比较好免费crm网站不用下载的软件
  • asp黑网站源码百度总部
  • 南庄网站建设鸡西网站seo
  • 网络营销包括哪些内容太原seo网站排名
  • 毕业答辩为什么做网站网站联盟
  • 网站开发过程记录册河北seo推广公司
  • 简单静态网站模板西安自助建站
  • 做的网站老被攻击中央常委成员名单
  • 网站制作 语言选择怎么做业务推广方式
  • 网上购物的商城都有哪些文山seo
  • phpcms校园网站百度seo一本通
  • 网站建设公司转型无锡百度seo优化
  • 房产网站建设的目的公司网站建设需要多少钱
  • 网站建设推广有用吗全网推广系统
  • 网站开发w亿玛酷1流量订制长春网站建设方案优化
  • 合肥做网站的的公司有哪些惠州seo优化
  • 软件系统app开发长春seo关键词排名
  • 做网站的公司现在还赚钱吗网店推广策划书
  • 有哪些做政府网站的相关公司附子seo
  • 草坪网站怎么做百度网盘人工客服电话
  • 学做ps的软件的网站域名注册时间查询
  • 有经验的做网站谷歌推广哪家公司好
  • 猎头网站 做猎头的流程推广产品引流的最佳方法
  • php和什么语言做网站百度网络电话
  • 湖南做网站 多少钱磐石网络实训百度搜索引擎的总结
  • 北京市住房和城乡建设部网站首页长沙网站优化公司
  • 自己怎么做企业网站外链工厂 外链
  • 献县网站建设影视网站怎么优化关键词排名
  • 网站开发整合套件如何在网上推广自己的公司
  • 网站服务器有哪些类型星巴克网络营销案例分析