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

济南做微网站推广互联网营销方案

济南做微网站推广,互联网营销方案,网站建设程序源码,美容网站制作目录 1. 为什么需要智能指针? 2. 内存泄漏 2.1 什么是内存泄漏,内存泄漏的危害 2.2 内存泄漏分类(了解) 堆内存泄漏(Heap leak) 系统资源泄漏 2.3 如何检测内存泄漏(了解) 2.4如何避免内存泄漏 3.…

目录

1. 为什么需要智能指针?

2. 内存泄漏

2.1 什么是内存泄漏,内存泄漏的危害

2.2 内存泄漏分类(了解)

堆内存泄漏(Heap leak)

系统资源泄漏

2.3 如何检测内存泄漏(了解)

2.4如何避免内存泄漏

3.智能指针的使用及原理

3.1 RAII

// 使用RAII思想设计的SmartPtr类

​编辑

std::auto_ptr

模拟实现

std::unique_ptr

​编辑

​编辑

模拟实现

​编辑

std::shared_ptr

模拟实现

 赋值(重要)

总代码 

循环引用问题

解决方法(weak_ptr不是智能指针)

模拟实现

测试:​编辑

make_shared

功能

语法

优点

示例

注意事项

定制删除器(用到了包装器)

 题目


1. 为什么需要智能指针?

下面我们先分析一下下面这段程序有没有什么内存方面的问题?提示一下:注意分析MergeSort函数中的问题。

因为div抛异常后会跳过delete,导致内存泄漏

int div()
{int a, b;cin >> a >> b;if (b == 0)throw invalid_argument("除0错误");return a / b;
}void Func()
{// 1、如果p1这里new 抛异常会如何?// 2、如果p2这里new 抛异常会如何?// 3、如果div调用这里又会抛异常会如何?int* p1 = new int;int* p2 = new int;cout << div() << endl;delete p1;delete p2;
}int main()
{try{Func();}catch (exception& e){cout << e.what() << endl;}return 0;
}

2. 内存泄漏

2.1 什么是内存泄漏,内存泄漏的危害

什么是内存泄漏:内存泄漏指因为疏忽或错误造成程序未能释放已经不再使用的内存的情况。内 存泄漏并不是指内存在物理上的消失,而是应用程序分配某段内存后,因为设计错误,失去了对 该段内存的控制,因而造成了内存的浪费。 内存泄漏的危害:长期运行的程序出现内存泄漏,影响很大,如操作系统、后台服务等等,出现 内存泄漏会导致响应越来越慢,最终卡死。

void MemoryLeaks()
{// 1.内存申请了忘记释放int* p1 = (int*)malloc(sizeof(int));int* p2 = new int;// 2.异常安全问题int* p3 = new int[10];Func(); // 这里Func函数抛异常导致 delete[] p3未执行,p3没被释放.delete[] p3;
}

2.2 内存泄漏分类(了解)

C/C++程序中一般我们关心两种方面的内存泄漏:

堆内存泄漏(Heap leak)

堆内存指的是程序执行中依据须要分配通过malloc / calloc / realloc / new等从堆中分配的一 块内存,用完后必须通过调用相应的 free或者delete 删掉。假设程序的设计错误导致这部分 内存没有被释放,那么以后这部分空间将无法再被使用,就会产生Heap Leak。

系统资源泄漏

指程序使用系统分配的资源,比方套接字、文件描述符、管道等没有使用对应的函数释放 掉,导致系统资源的浪费,严重可导致系统效能减少,系统执行不稳定。

2.3 如何检测内存泄漏(了解)

在linux下内存泄漏检测:Linux下几款C++程序中的内存泄露检查工具_c++内存泄露工具分析-CSDN博客

在windows下使用第三方工具:VS编程内存泄漏:VLD(Visual LeakDetector)内存泄露库_visual leak detector vs2020-CSDN博客

其他工具:内存泄露检测工具比较 - 默默淡然 - 博客园

2.4如何避免内存泄漏

1. 工程前期良好的设计规范,养成良好的编码规范,申请的内存空间记着匹配的去释放。ps: 这个理想状态。但是如果碰上异常时,就算注意释放了,还是可能会出问题。需要下一条智 能指针来管理才有保证。

2. 采用RAII思想或者智能指针来管理资源。

3. 有些公司内部规范使用内部实现的私有内存管理库。这套库自带内存泄漏检测的功能选项。

4. 出问题了使用内存泄漏工具检测。ps:不过很多工具都不够靠谱,或者收费昂贵。 总结一下:

内存泄漏非常常见,解决方案分为两种:1、事前预防型。如智能指针等。2、事后查错型。如泄 漏检测工具。

3.智能指针的使用及原理

3.1 RAII

RAII(Resource Acquisition Is Initialization)是一种利用对象生命周期来控制程序资源(如内 存、文件句柄、网络连接、互斥量等等)的简单技术。

在对象构造时获取资源,接着控制对资源的访问使之在对象的生命周期内始终保持有效,最后在 对象析构的时候释放资源。借此,我们实际上把管理一份资源的责任托管给了一个对象。这种做 法有两大好处:

不需要显式地释放资源。

采用这种方式,对象所需的资源在其生命期内始终保持有效。

// 使用RAII思想设计的SmartPtr类

int div()
{int a, b;cin >> a >> b;if (b == 0)throw invalid_argument("除0错误");return a / b;
}
//这样就不用担心没有释放了
template<class T>
class SmartPtr
{
public:// RAII// 资源交给对象管理,对象生命周期内,资源有效,对象生命周期到了,释放资源// 1、RAII管控资源释放// 2、像指针一样SmartPtr(T* ptr):_ptr(ptr){}~SmartPtr(){cout << "delete:" << _ptr << endl;delete _ptr;}T& operator*(){return *_ptr;}T* operator->(){return _ptr;}
private:T* _ptr;
};
void f()
{//new,也可能有很小的概率出问题SmartPtr<pair<string, string>> sp1(new pair<string, string>("1111", "22222"));//这里div抛异常后,sp1会释放,然后直接跳过进入main中不进入,sp2,sp3,只要是f结束,f中的new后都//会调用deletediv();SmartPtr<pair<string, string>> sp2(new pair<string, string>);SmartPtr<pair<string, string>> sp3(new pair<string, string>);SmartPtr<string> sp4(new string("xxxxx"));/*cout << *sp4 << endl;cout << sp1->first << endl;cout << sp1->second << endl;*///这里div抛异常后,sp1和sp2,sp3都会释放div();//delete p1;//cout << "delete:" << p1 << endl;
}
int main()
{try{f();}catch (const exception& e){cout << e.what() << endl;}catch (...){cout << "Unkown Exception" << endl;}return 0;
}

没写赋值,浅拷贝(深拷贝也没法解决问题),把sp2的值给了sp1,只释放了一个,还有一个没释放,发生了内存泄漏 

c++中new了要delete

有了异常以后,已经不可控了,因为抛异常会影响执行流,会改变程序执行顺序

智能指针


using namespace std;
int div()
{int a, b;cin >> a >> b;if (b == 0)throw invalid_argument("除0错误");return a / b;
}
//这样就不用担心没有释放了
template<class T>
class SmartPtr
{
public:// RAII// 资源交给对象管理,对象生命周期内,资源有效,对象生命周期到了,释放资源// 1、RAII管控资源释放// 2、像指针一样SmartPtr(T* ptr):_ptr(ptr){}~SmartPtr(){cout << "delete:" << _ptr << endl;delete _ptr;}T& operator*(){return *_ptr;}T* operator->(){return _ptr;}
private:T* _ptr;
};
void f()
{//new,也可能有很小的概率出问题SmartPtr<pair<string, string>> sp1(new pair<string, string>("1111", "22222"));//这里div抛异常后,sp1会释放,然后直接跳过进入main中不进入,sp2,sp3,只要是f结束,f中的new后都//会调用deletediv();SmartPtr<pair<string, string>> sp2(new pair<string, string>);SmartPtr<pair<string, string>> sp3(new pair<string, string>);SmartPtr<string> sp4(new string("xxxxx"));/*cout << *sp4 << endl;cout << sp1->first << endl;cout << sp1->second << endl;*///这里div抛异常后,sp1和sp2,sp3都会释放div();//delete p1;//cout << "delete:" << p1 << endl;}int main()
{try{f();}catch (const exception& e){cout << e.what() << endl;}catch (...){cout << "Unkown Exception" << endl;}return 0;
}

std::auto_ptr

文档  https://cplusplus.com/reference/memory/auto_ptr/

auto_ptr是一个失败设计,很多公司明确要求不能使用auto_ptr

会导致悬空问题,实质上是管理权限的转移

C++98版本的库中就提供了auto_ptr的智能指针。下面演示的auto_ptr的使用及问题。

auto_ptr的实现原理:管理权转移的思想,下面简化模拟实现了一份bit::auto_ptr来了解它的原 理

// C++98 管理权转移 auto_ptr

int main()
{//这种形式跟上面自己写的Smartptr类似auto_ptr<int> at1(new int);//这个auto_ptr拷贝后会出现大问题,会出现悬空问题auto_ptr<int> at2(at1);//管理权限的转移*at2 = 10;cout << *at2 << endl;//*at1 = 10;会报错,因为*at1已经悬空*at1 = 10;cout << *at1 << endl;return 0;
}

模拟实现

namespace Ljw
{template<class T>class auto_ptr{public:auto_ptr(T* ptr):_ptr(ptr){}~auto_ptr(){cout << "~auto_ptr" << endl;if (_ptr){delete _ptr;}}T& operator*(){return *_ptr;}T* operator->(){return _ptr;}//重点在于拷贝auto_ptr(auto_ptr<T>& ptr):_ptr(ptr._ptr){//这里就是悬空了,管理权转ptr._ptr = nullptr;}private:T* _ptr;};
}

std::unique_ptr

C++11中开始提供更靠谱的unique_ptr

文档:https://cplusplus.com/reference/memory/unique_ptr/

unique_ptr的实现原理:简单粗暴的防拷贝,下面简化模拟实现了一份UniquePtr来了解它的原 理

/ C++11库才更新智能指针实现

// C++11出来之前,boost搞除了更好用的scoped_ptr/shared_ptr/weak_ptr // C++11将boost库中智能指针精华部分吸收了过来

// C++11->unique_ptr/shared_ptr/weak_ptr // unique_ptr/scoped_ptr // 原理:简单粗暴 -- 防拷贝

模拟实现

template<class T>
class unique_ptr
{
public://默认构造unique_ptr(T*ptr):_ptr(ptr){}~unique_ptr(){delete _ptr;}T& operator*(){return *_ptr;}T* operator->(){return _ptr;}//直接用delete禁止拷贝构造unique_ptr(unique_ptr<T>& ptr) = delete;//直接用delete禁止赋值unique_ptr<T>& operator=(unique_ptr<T>& ptr) = delete;
private:T* _ptr;
};

std::shared_ptr

C++11中开始提供更靠谱的并且支持拷贝的shared_ptr

文档:https://cplusplus.com/reference/memory/shared_ptr/

shared_ptr的原理:是通过引用计数的方式来实现多个shared_ptr对象之间共享资源。例如: 老师晚上在下班之前都会通知,让最后走的学生记得把门锁下。

1. shared_ptr在其内部,给每个资源都维护了着一份计数,用来记录该份资源被几个对象共 享。

2. 在对象被销毁时(也就是析构函数调用),就说明自己不使用该资源了,对象的引用计数减 一。

3. 如果引用计数是0,就说明自己是最后一个使用该资源的对象,必须释放该资源;

4. 如果不是0,就说明除了自己还有其他对象在使用该份资源,不能释放该资源,否则其他对象就成野指针了。

// 引用计数支持多个拷贝管理同一个资源,最后一个析构对象释放资源

原理图

模拟实现

用指针创建空间进行计数保存是合理的,静态全局的也是不符合的。

重点

 赋值(重要)

步骤1:先把sp1和sp3弄成共同资源,先把sp2和sp4和sp5弄成共同资源

经过测试后,实际只有释放一个空间

//赋值
//要考虑到前后计数要改变
//如果到0了也是需要直接释放的
//如果是同一块资源赋值可以不用处理
//同一块资源的判定条件是
shared_ptr<T>& operator=(shared_ptr<T>& ptr)
{//同一块资源if (_ptr == ptr._ptr)return *this;//赋值的时候,this的空间计数就少了1(*_count)--;if (*(_count) == 0){delete _ptr;delete _count;}//先增加计数也一样然后ptr的空间资源计数就多了1//(*ptr._count)++;//赋值_ptr = ptr._ptr;_count = ptr._count;//然后ptr的空间资源计数就多了1(*_count)++;return *this;
}

总代码 

template<class T>
class shared_ptr
{
public://默认构造shared_ptr(T* ptr=nullptr):_ptr(ptr),_count(new int(1))//这里_count是指针,要单独开一个空间,进行管理{}~shared_ptr(){(*_count)--;if ((* _count) == 0){cout << "~shared_ptr" << endl;delete _ptr;delete _count;}	}T& operator*(){return *_ptr;}T* operator->(){return _ptr;}//sp2(sp1)shared_ptr(shared_ptr<T>& ptr):_ptr(ptr._ptr),_count(ptr._count){(*_count)++;}//赋值//要考虑到前后计数要改变//如果到0了也是需要直接释放的//如果是同一块资源赋值可以不用处理//同一块资源的判定条件是shared_ptr<T>& operator=(shared_ptr<T>& ptr){//同一块资源if (_ptr == ptr._ptr)return *this;//赋值的时候,this的空间计数就少了1(*_count)--;if (*(_count) == 0){delete _ptr;delete _count;}//先增加计数也一样然后ptr的空间资源计数就多了1//(*ptr._count)++;//赋值_ptr = ptr._ptr;_count = ptr._count;//然后ptr的空间资源计数就多了1(*_count)++;return *this;}int use_count() const{return *_count;}T* get() const{return _ptr;}
private:T* _ptr;//计数int* _count;
};

循环引用问题

Node手动释放版本

delete n1上面如果抛异常了呢,所以就需要智能指针

这里报错的原因(类型不匹配)是因为一个自定义类型一个内置类型,要把上面的也改成智能指针,所以要改成如下图

正常释放(shared_ptr)

这样就发生了循环引用,没法正常释放空间,屏蔽其中一个就没问题,但两个都有就不行了

解决方法(weak_ptr不是智能指针)

/ 解决方案:在引用计数的场景下,把节点中的_prev和_next改成weak_ptr就可以了

// 原理就是,node1->_next = node2;和node2->_prev = node1;时weak_ptr的_next和

_prev不会增加node1和node2的引用计数。

模拟实现

template<class T>
class weak_ptr
{
public:weak_ptr():_ptr(nullptr){}weak_ptr(const shared_ptr<T>& sp):_ptr(sp.get()){}weak_ptr<T>& operator=(const shared_ptr<T>& sp){_ptr = sp.get();return *this;}T& operator*(){return *_ptr;}T* operator->(){return _ptr;}
private:T* _ptr;
};

测试:

make_shared

make_shared 是 C++11 标准库中引入的一个模板函数,它属于 <memory> 头文件中定义的智能指针工具集。make_shared 的主要目的是简化智能指针的创建过程,并可能提供性能上的优化。

以下是 make_shared 的一些关键点:

功能

  • make_shared 用于创建一个 std::shared_ptr 对象,该对象管理动态分配的对象。
  • 它接受一个类型参数以及该类型构造函数所需的参数,并返回一个 shared_ptr 指向新创建的对象。

语法

template< class T, class... Args >
shared_ptr<T> make_shared( Args&&... args );

优点

  1. 简洁性make_shared 允许你在一条语句中创建和管理动态分配的对象,而不需要分别写 new 和 shared_ptr 的构造函数。

  2. 性能优化make_shared 通常比直接使用 new 分配内存再包装成 shared_ptr 更高效。这是因为 make_shared 只需要在堆上分配一次内存,即同时为对象本身和共享的引用计数(控制块)分配空间。而直接使用 new 和 shared_ptr 的构造函数通常需要两次内存分配:一次为对象本身,另一次为控制块。

  3. 异常安全:当使用 new 分配内存并将结果传递给 shared_ptr 的构造函数时,如果在参数传递过程中发生异常,可能会导致内存泄漏。使用 make_shared 可以避免这种风险,因为 new 和 shared_ptr 的构造是在一个操作中完成的。

示例

下面是使用 make_shared 创建 std::shared_ptr 的一个例子:

#include <memory>
#include <iostream>class MyClass {
public:MyClass(int a, int b) : x(a), y(b) {}void print() const { std::cout << x << " " << y << std::endl; }private:int x, y;
};int main() {auto mySharedPtr = std::make_shared<MyClass>(10, 20);mySharedPtr->print(); // 输出: 10 20return 0;
}

注意事项

  • make_shared 不能用于管理动态分配的数组,因为这会导致 shared_ptr 的析构函数使用错误的删除器(delete 而不是 delete[])。
  • 当需要指定自定义的删除器时,使用 std::allocate_shared 而不是 make_shared
  • 在某些情况下,make_shared 可能不是最佳选择,特别是当传递的参数涉及到类型转换或需要绑定引用时。

make_shared 是 C++ 中管理动态内存时非常有用的工具,可以减少代码量并提高性能。然而,了解其使用限制和最佳实践是编写高效、安全代码的关键。

定制删除器(用到了包装器)

unique和shared都有定制删除器

因为底层是delete,所以[ ]的释放要实现一个删除器

在shared_ptr中总代码

template<class T>
class shared_ptr
{
public://默认构造shared_ptr(T* ptr=nullptr):_ptr(ptr),_count(new int(1))//这里_count是指针,要单独开一个空间,进行管理{}template<class D>shared_ptr(T* ptr, D del)//这里就不可以加缺省值nullptr了,因为是从右到左的:_ptr(ptr), _count(new int(1))//这里_count是指针,要单独开一个空间,进行管理,_del(del){}~shared_ptr(){(*_count)--;if ((* _count) == 0){cout << "~shared_ptr" << endl;_del(_ptr);delete _count;}	}T& operator*(){return *_ptr;}T* operator->(){return _ptr;}//sp2(sp1)shared_ptr(shared_ptr<T>& ptr):_ptr(ptr._ptr),_count(ptr._count){(*_count)++;}//赋值//要考虑到前后计数要改变//如果到0了也是需要直接释放的//如果是同一块资源赋值可以不用处理//同一块资源的判定条件是shared_ptr<T>& operator=(shared_ptr<T>& ptr){//同一块资源if (_ptr == ptr._ptr)return *this;//赋值的时候,this的空间计数就少了1(*_count)--;if (*(_count) == 0){delete _ptr;delete _count;}//先增加计数也一样然后ptr的空间资源计数就多了1//(*ptr._count)++;//赋值_ptr = ptr._ptr;_count = ptr._count;//然后ptr的空间资源计数就多了1(*_count)++;return *this;}int use_count() const{return *_count;}T* get() const{return _ptr;}
private:T* _ptr;//计数int* _count;//删除器function<void(T*)> _del = [](T* ptr) {delete ptr; };
};

如果不是new出来的对象如何通过智能指针管理呢?其实shared_ptr设计了一个删除器来解决这 个问题(ps:删除器这个问题我们了解一下)

// 仿函数的删除器

// 仿函数的删除器template<class T>struct FreeFunc {void operator()(T* ptr){cout << "free:" << ptr << endl;free(ptr);}
};template<class T>struct DeleteArrayFunc {void operator()(T* ptr){ cout << "delete[]" << ptr << endl;delete[] ptr; }
};int main()
{FreeFunc<int> freeFunc;std::shared_ptr<int> sp1((int*)malloc(4), freeFunc);DeleteArrayFunc<int> deleteArrayFunc;std::shared_ptr<int> sp2((int*)malloc(4), deleteArrayFunc);std::shared_ptr<A> sp4(new A[10], [](A* p){delete[] p; });std::shared_ptr<FILE> sp5(fopen("test.txt", "w"), [](FILE* p)
{fclose(p); });return 0;
}

 题目

1:

weak_ptr不能单独管理资源,必须配合shared_ptr一块使用,解决shared_ptr中存在的 循环引用问题

RAII的实现方式就是在构造函数中将资源初始化,在析构函数中将资源清理掉

RAII方式管理资源,可以有效避免资源泄漏问题

RAII方式管理锁,有些场景下可以有效避免死锁问题

2:

A.auto_ptr智能指针是在C++98版本中已经存在的

B.auto_ptr的多个对象之间,不能共享资源

C.auto_ptr的实现原理是资源的转移

3:

C++11中提供的智能指针都只能管理单个对象的资源,没有提供管理一段空间资源的智能指针

A.unique_ptr是C++11才正式提出的

C.unique_ptr不能使用其拷贝构造函数

D.unique_ptr的对象之间不能相互赋值

4:

有些场景下shared_ptr可能会造成循环引用,必须与weak_ptr配合使用

A.shared_ptr是C++11才正式提出来的

B.shared_ptr对象之间可以共享资源

D.shared_ptr是借助引用计数的方式实现的

5:

weak_ptr不能单独管理资源,因为其给出的最主要的原因是配合shared_ptr解决其循环 引用问题

weak_ptr和shared_ptr都是通过引用计数实现,但是在底层还是有区别的

weak_ptr的唯一作用就是解决shared_ptr中存在的循环引用问题,处理解决shared_ptr的循环引用问题外,别无它用

http://www.hrbkazy.com/news/39994.html

相关文章:

  • 卖挂的网站怎么做西安网站制作公司
  • 宝鸡企业网站建设免费网络推广方式
  • 网站怎么做搜索功能哪些平台可以打小广告
  • 台湾网站建设百度手机助手app下载并安装
  • 用手机怎么看自己做的网站国内免费建站平台
  • 杭州旅游 网站建设互联网项目
  • 品牌建设中企业要注意哪些问题seop
  • 网站设计开发平台新品上市的营销方案
  • 手机做直播官方网站外链图片
  • 中山企业网站建设搭建网站基本步骤
  • 广州品牌设计网站建设百度竞价排名是什么方式
  • 广州门户网站开发微信广告推广平台
  • Wordpress循环一行3个divseo关键词报价查询
  • 网站 ca证书怎么做广州网站优化软件
  • 手机网站收费最近10个新闻
  • 免费网站建设教程视频bt磁力猫
  • 网站的后台登录注册怎么做盐城seo推广
  • 南沙做网站今日国际军事新闻
  • 做网站系统具体步骤西安网络推广公司大全
  • 扫码进入网站 怎么做微信群发软件
  • 网站域名年费seo网站优化培训
  • 郑州网站优化外包顾问网络整合营销公司
  • nba最新排名官网网站seo入门基础教程书籍
  • 做网站首选九零后网络微信公众号软文怎么写
  • 网站如何和其他网站做友情链接泾县网站seo优化排名
  • 怎样建立自己购物网站百度应用商店下载
  • 做网站后期怎么维护女教师遭网课入侵直播录屏曝
  • b2c商城网站建设 工具深圳网络营销推广外包
  • 咸阳公司做网站做一个公司网站要多少钱
  • 网站的建设目标文档国内it培训机构排名