ICode9

精准搜索请尝试: 精确搜索
首页 > 编程语言> 文章详细

C++智能指针

2021-09-23 17:03:06  阅读:115  来源: 互联网

标签:对象 C++ 智能 内存 new shared ptr 指针



typora-copy-images-to: ./

智能指针知识总结:

来源cpp,自己总结复习用。

对象与内存


内存分布:

  • 静态内存:局部static对象,类static数据成员,函数之外定义的变量。
  • 栈内存:定义在函数内的非static对象。
  • 内存池(自由空间,堆):动态分配对象——运行时分配的对象。

自动和static对象的内存管理:

  • 全局对象,程序启动时分配内存,程序结束时释放内存。

  • 局部自动对象,进入定义的程序块后分配内存,离开块之后释放内存。

  • 局部static对象,首次使用前分配内存,程序结束时释放内存。

动态分配对象的内存管理:

  • 生存期与在哪里创建无关,只有显式释放后对象才被销毁。

  • 直接管理内存运算符new,动态内存中分配空间并返回一个指向该对象的指针。

  • 直接管理内存运算符delete,接受一个指向动态对象的指针,销毁对象并释放关联内存。

  • 问题1:忘记释放内存,会造成内存泄露。

  • 问题2:指针引用内存下释放内存,会引用非法内存的指针。

智能指针:用于更安全地使用动态对象,因为动态分配对象的正确释放很难掌控,标准库就定义了两种智能指针类型,帮助我们自动释放一个对象。智能指针定义在中,使用方法同模板。


直接管理内存new和delete的使用:

new

堆中分配的内存是无名的,new无法为分配对象命名,因此new会返回一个指向对象的指针。动态分配的对象是默认初始化的。

int *ip = new int;//内置类型,默认初始化为未定义。
int *ip2 = new int();//内置类型,值初始化为0。


//同string类似的类类型,其有默认构造,不论哪种形式都会初始化。
string *s = new string; 
string *s2 = new string(); 

//用auto初始化器推断分配类型,只能提供单一初始化器。
auto p = new auto(obj);

若堆内存耗尽,使用new会抛出一个类型为std::bad_alloc的异常。我们使用定位new(placement new)阻止。它们都存在于new头文件中。

int *p = new (nothrow) int ;//分配失败会返回一个空指针。

delete

传递给delete的指针,要么是指向动态分配的内存,要么为空。注意:编译器不能分辨指针指向静态还是动态分配对象,同时也不知道指向内存是否已经释放。

内置指针类型管理内存:

  • 需要调用者或者函数本身释放该内存,否则会发生内存泄漏。
  • 我们最好在delete操作后,将指针置为空来检测错误。
  • 同一块内存被先后释放两次,堆会被破坏。

关于第二点,因为delete后指针仍然指向已释放的动态内存的地址,此时指针为空悬指针。我们不能继续使用该指针,因此需要置为空而不绑定到任何对象。同时,delete只对当前指针有效,而对其他指向同一对象的指针无效。


shared_ptr:

管理方式:允许多个指针指向同一个对象。

安全分配和使用动态内存的函数:make_shared,该函数返回一个shared_ptr。

//创建一个智能指针
shared_ptr<T> pointer; //执行默认初始化保存一个空指针

//使用make_shared创建一个智能指针,传递参数必须要匹配对象的构造函数
shared_ptr<T> pointer2 = make_shared<T>(); //执行值初始化
shared_ptr<int> pointer3 = make_shared<int>(2); //该智能指针指向一个值为2的int对象

拷贝或赋值操作,每个shared_ptr有个关联的计数器(引用次数),会记录有多少个其它shared_ptr指向相同的对象。

shared_ptr<int> p = make_shared<int>(2); //对象引用计数1.
auto r = p; //赋值操作,对象引用计数+1,结果为2.

auto q = make_shared<int>(3); //指向值为3的int对象的引用次数1.
q = r ; // 没有指向值为3的int对象,引用次数0,自动释放管理对象。

如何自动销毁管理对象:通过析构函数,该函数会销毁、释放对象所分配的资源。shared_ptr每次执行析构函数,都会递减以此引用次数,所以当引用次数为0时,就会销毁对象,释放内存。

自动释放关联内存:shared_ptr销毁前内存都不会释放,所以不用之后需要销毁。比如容器中存放智能指针,容器重排后智能指针不再使用,但是指针指向的对象仍然被引用。

使用动态内存原因:

  1. 程序不知道自己需要使用多少对象。
  2. 程序不知道对象的准确类型。
  3. 程序需要在多个对象间共享数据。

shared_ptr与new的结合使用:

//使用new返回的指针初始化智能指针,但必须为显式初始化,因为内置指针不能隐式转换为智能指针。
shared_ptr<T> p(new int(1024));	//显式转换

//常见错误,shared_ptr临时对象使用内置指针构造。
int *i(new int(1024));
void process(shared_ptr<int> (i));
//process块结束后,智能指针自动析构,i成为了悬浮指针。


//智能指针的get函数可以返回一个内置指针,考虑到上述错误,我们不应该用该指针初始化或赋值智能指针,也不应该delete该内置指针。
shared_ptr<int> p2(new int(512));
int *p3 = p2.get();

//reset操作,可以使智能指针指向新对象。

函数退出有两种可能:正常处理结束或异常退出。使用内置指针管理内存时,若在new和delete之间发生了异常,由于异常退出,不会执行delete操作,因此内存不会释放。

有些基于C和C++的类,没有良好的析构函数,需要我们自己进行释放操作。使用智能指针管理的内容不是new分配的内存,则需要根据该类传递一个删除器。

shared_ptr<T> P(q,deleter) //p接管q指向的内容,deleter为可调用对象(删除器)

unique_ptr:

管理方式:独占所指动态对象,需要绑定到new返回的指针上。当其被销毁时指向对象也被销毁,与shared_ptr不同,例如拷贝的shared_ptr,其被销毁只使引用次数递减。

初始化方式:与shared_ptr类似,我们要显示初始化。但又有不同,因为unique_ptr的管理方式,我们不能使用拷贝和赋值操作。

unique_ptr<int> p(new int(1024));

也可以通过release释放操作/reset重定操作,绑定到另一个unique_ptr上。

unique_ptr<int> p2(p.release()); //release返回p指向的对象的指针

unique_ptr<int> p3(new int(512);
p2.reset(p3.release());			//reset操作将释放其原指向的对象
/*                   
p2.release(); //单独的释放指针控制权,不能对资源进行释放。 */
delete p2;	//需要使用直接管理内存的方式显式删除unique_ptr

unique_ptr可以拷贝或赋值一个即将被销毁的unique_ptr,如可从函数中返回一个unique_ptr.

重载unique_ptr的默认删除器:

unique_ptr<objT,delT> p (new objT,fcn);//delT对象用于释放objT对象,fcn为delT类型的对象

weak_ptr:

管理方式:伴随类&弱引用,指向shared_ptr所管理的对象,但不控制对象的生存期,所以其创建不会对shared_ptr引用次数有影响,进一步地说,其指向的对象还存不存在都不确定。

初始化方式:使用一个shared_ptr初始化。或者隐式初始化为空。

shared_ptr<int> p(new int(1024));
weak_ptr<int> p2(p);

由于其管理方式,我们需要确认unique_ptr其指向对象是否存在,使用lock来检查。

if(shared_ptr<int> p = p2.lock()){
	//使用p安全访问对象
}

有了lock,我们可以使用weak_ptr写一个伴随指针类,该类不会影响被伴随类资源的生存周期,但是可以检查被伴随类的资源从而阻止访问部分资源。

标签:对象,C++,智能,内存,new,shared,ptr,指针
来源: https://blog.csdn.net/MAXXD/article/details/120438610

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有