字符数组的指针如何定义_指针指向数组

字符数组的指针如何定义_指针指向数组C++ 智能指针 – 全部用法详解为什么要学习智能指针?咳咳,这个问题不是问大家的,是询问我自己的!我依稀记得刚离校出来找实习工作那会,去面试一份工作,其中有一个环节需要答题;有一道题目就是问什么是智能指针?卧槽?当时我就懵逼,智能指针我压根就没

C++ 智能指针 – 全部用法详解   为什么要学习智能指针?   咳咳,这个问题不是问大家的,是询问我自己的!   我依稀记得刚离校出来找实习工作那会,去面试一份工作,其中有一个环节需要答题;有一道题目就是问什么是智能指针?卧槽?当时我就懵逼,智能指针我压根就没有听说过…   最后,面试的这份工作理所应当的黄了。   差不多是一年前左右吧,现在趁有闲余时间,学习一下智能指针,丰富一下自己!   一、为什么要使用智能指针   一句话带过:智能指针就是帮我们C++程序员管理动态分配的内存的,它会帮助我们自动释放new出来的内存,从而避免内存泄漏!   如下例子就是内存泄露的例子:   memoryLeak1函数中,new了一个字符串指针,但是没有delete就已经return结束函数了,导致内存没有被释放,内存泄露!   memoryLeak2函数中,new了一个字符串指针,虽然在函数末尾有些释放内存的代码delete str,但是在delete之前就已经return了,所以内存也没有被释放,内存泄露!   使用指针,我们没有释放,就会造成内存泄露。但是我们使用普通对象却不会!   思考:如果我们分配的动态内存都交由有生命周期的对象来处理,那么在对象过期时,让它的析构函数删除指向的内存,这看似是一个 very nice 的方案?   智能指针就是通过这个原理来解决指针自动释放的问题!   C++98 提供了 auto_ptr 模板的解决方案   C++11 增加unique_ptr、shared_ptr 和weak_ptr   二、auto_ptr   auto_ptr 是c++ 98定义的智能指针模板,其定义了管理指针的对象,可以将new 获得(直接或间接)的地址赋给这种对象。当对象过期时,其析构函数将使用delete 来释放内存!   用法:   头文件: #include < memory >   用 法: auto_ptr<类型> 变量名(new 类型)   例 如:   auto_ptr< string > str(new string(“我要成为大牛~ 变得很牛逼!”));   auto_ptr<vector< int >> av(new vector< int >());   auto_ptr< int > array(new int[10]);   例:   我们先定义一个类,类的构造函数和析构函数都输出一个字符串用作提示!   定义一个私有成员变量,赋值20.   再定义一个私有成员方法用于返回这个私有成员变量。   当我们直接new这个类的对象,却没有释放时。。。   
字符数组的指针如何定义_指针指向数组
字符数组的指针如何定义_指针指向数组   可以看到,只是打印了构造函数这个字符串,而析构函数的字符却没有被打印,说明并没有调用析构函数!这就导致了内存泄露!   解决内存泄露的办法,要么手动delete,要么使用智能指针!   使用智能指针:   智能指针可以像普通指针那样使用:   这时再试试:   
字符数组的指针如何定义_指针指向数组
字符数组的指针如何定义_指针指向数组   自动调用了析构函数。   为什么智能指针可以像普通指针那样使用???   因为其里面重载了 * 和 -> 运算符, * 返回普通对象,而 -> 返回指针对象。
字符数组的指针如何定义_指针指向数组
字符数组的指针如何定义_指针指向数组   具体原因不用深究,只需知道他为什么可以这样操作就像!函数中返回的是调用get()方法返回的值,那么这个get()是什么呢?   智能指针的三个常用函数:get() 智能指针托管的指针地址.   但我们一般不会这样使用,因为都可以直接使用智能指针去操作,除非有一些特殊情况。函数原型:   release() 取消智能指针对动态内存的托管   也就是智能指针不再对该指针进行管理,改由管理员进行管理!   函数原型:   reset() 重置智能指针托管的内存地址,如果地址不一致,原来的会被析构掉   reset函数会将参数的指针(不指定则为NULL),与托管的指针比较,如果地址不一致,那么就会析构掉原来托管的指针,然后使用参数的指针替代之。然后智能指针就会托管参数的那个指针了。   函数原型:   reset函数会将参数的指针(不指定则为NULL),与托管的指针比较,如果地址不一致,那么就会析构掉原来托管的指针,然后使用参数的指针替代之。然后智能指针就会托管参数的那个指针了。函数原型:   使用建议:尽可能不要将auto_ptr 变量定义为全局变量或指针;   除非自己知道后果,不要把auto_ptr 智能指针赋值给同类型的另外一个 智能指针;   C++11 后auto_ptr 已经被“抛弃”,已使用unique_ptr替代!C++11后不建议使用auto_ptr。auto_ptr 被C++11抛弃的主要原因1). 复制或者赋值都会改变资源的所有权   
字符数组的指针如何定义_指针指向数组
字符数组的指针如何定义_指针指向数组   2). 在STL容器中使用auto_ptr存在着重大风险,因为容器内的素必须支持可复制和可赋值   访问越界了!
字符数组的指针如何定义_指针指向数组
字符数组的指针如何定义_指针指向数组   3). 不支持对象数组的内存管理   
字符数组的指针如何定义_指针指向数组
字符数组的指针如何定义_指针指向数组   所以,C++11用更严谨的unique_ptr 取代了auto_ptr!   测试代码:   三、unique_ptr   auto_ptr是用于C++11之前的智能指针。由于 auto_ptr 基于排他所有权模式:两个指针不能指向同一个资源,复制或赋值都会改变资源的所有权。auto_ptr 主要有三大问题:   复制和赋值会改变资源的所有权,不符合人的直觉。   在 STL 容器中使用auto_ptr存在重大风险,因为容器内的素必需支持可复制(copy constructable)和可赋值(assignable)。   不支持对象数组的操作   以上问题已经在上面体现出来了,下面将使用unique_ptr解决这些问题。   所以,C++11用更严谨的unique_ptr 取代了auto_ptr!   unique_ptr 和 auto_ptr用法几乎一样,除了一些特殊。   unique_ptr特性   基于排他所有权模式:两个指针不能指向同一个资源   无法进行左值unique_ptr复制构造,也无法进行左值复制赋值操作,但允许临时右值赋值构造和赋值   保存指向某个对象的指针,当它本身离开作用域时会自动释放它指向的对象。   在容器中保存指针是安全的   A. 无法进行左值复制赋值操作,但允许临时右值赋值构造和赋值   
字符数组的指针如何定义_指针指向数组
字符数组的指针如何定义_指针指向数组   运行截图:
字符数组的指针如何定义_指针指向数组
字符数组的指针如何定义_指针指向数组   B. 在 STL 容器中使用unique_ptr,不允许直接赋值   
字符数组的指针如何定义_指针指向数组
字符数组的指针如何定义_指针指向数组   当然,运行后是直接报错的,因为vec[1]已经是NULL了,再继续访问就越界了。   C. 支持对象数组的内存管理   除了上面ABC三项外,unique_ptr的其余用法都与auto_ptr用法一致。构造   赋值   主动释放对象   放弃对象的控制权   重置   auto_ptr 与 unique_ptr智能指针的内存管理陷阱   
字符数组的指针如何定义_指针指向数组
字符数组的指针如何定义_指针指向数组   这是由于auto_ptr 与 unique_ptr的排他性所导致的!   为了解决这样的问题,我们可以使用shared_ptr指针指针!   四、shared_ptr   熟悉了unique_ptr 后,其实我们发现unique_ptr 这种排他型的内存管理并不能适应所有情况,有很大的局限!如果需要多个指针变量共享怎么办?   如果有一种方式,可以记录引用特定内存对象的智能指针数量,当复制或拷贝时,引用计数加1,当智能指针析构时,引用计数减1,如果计数为零,代表已经没有指针指向这块内存,那么我们就释放它!这就是 shared_ptr 采用的策略!
字符数组的指针如何定义_指针指向数组
字符数组的指针如何定义_指针指向数组   例:   引用计数的使用   调用use_count函数可以获得当前托管指针的引用计数。   如上代码,sp1 = sp2; 和 shared_ptr< Person > sp3(sp1);就是在使用引用计数了。   sp1 = sp2; –> sp1和sp2共同托管同一个指针,所以他们的引用计数为2;   shared_ptr< Person > sp3(sp1); –> sp1和sp2和sp3共同托管同一个指针,所以他们的引用计数为3;
字符数组的指针如何定义_指针指向数组
字符数组的指针如何定义_指针指向数组   构造   1). shared_ptr< T > sp1; 空的shared_ptr,可以指向类型为T的对象   2). shared_ptr< T > sp2(new T()); 定义shared_ptr,同时指向类型为T的对象   3). shared_ptr<T[]> sp4; 空的shared_ptr,可以指向类型为T[]的数组对象 C++17后支持   4). shared_ptr<T[]> sp5(new T[] { … }); 指向类型为T的数组对象 C++17后支持   5). shared_ptr< T > sp6(NULL, D()); //空的shared_ptr,接受一个D类型的删除器,使用D释放内存   6). shared_ptr< T > sp7(new T(), D()); //定义shared_ptr,指向类型为T的对象,接受一个D类型的删除器,使用D删除器来释放内存   初始化   1). 方式一:构造函数   2).方式二:使用make_shared 初始化对象,分配内存效率更高(推荐使用)   make_shared函数的主要功能是在动态内存中分配一个对象并初始化它,返回指向此对象的shared_ptr; 用法:   make_shared<类型>(构造类型对象需要的参数列表);   赋值   主动释放对象   重置   p.reset() ; 将p重置为空指针,所管理对象引用计数 减1   p.reset(p1); 将p重置为p1(的值),p 管控的对象计数减1,p接管对p1指针的管控   p.reset(p1,d); 将p重置为p1(的值),p 管控的对象计数减1并使用d作为删除器   p1是一个指针!   交换p1 和 p2 是智能指针   shared_ptr使用陷阱   shared_ptr作为被管控的对象的成员时,小心因循环引用造成无法释放资源!   如下代码:Boy类中有Girl的智能指针;Girl类中有Boy的智能指针;当他们交叉互相持有对方的管理对象时…   运行截图:
字符数组的指针如何定义_指针指向数组
字符数组的指针如何定义_指针指向数组   可以看出,程序结束了,但是并没有释放内存,这是为什么呢???   如下图:当我们执行useTrap函数时,注意,是没有结束此函数,boy和girl指针其实是被两个智能指针托管的,所以他们的引用计数是2
字符数组的指针如何定义_指针指向数组
字符数组的指针如何定义_指针指向数组   useTrap函数结束后,函数中定义的智能指针被清掉,boy和girl指针的引用计数减1,还剩下1,对象中的智能指针还是托管他们的,所以函数结束后没有将boy和gilr指针释放的原因就是于此。
字符数组的指针如何定义_指针指向数组
字符数组的指针如何定义_指针指向数组   所以在使用shared_ptr智能指针时,要注意避免对象交叉使用智能指针的情况! 否则会导致内存泄露!   当然,这也是有办法解决的,那就是使用weak_ptr弱指针。   针对上面的情况,还讲一下另一种情况。如果是单方获得管理对方的共享指针,那么这样着是可以正常释放掉的!例如:   
字符数组的指针如何定义_指针指向数组
字符数组的指针如何定义_指针指向数组   反过来也是一样的!   这是什么原理呢?   首先释放spBoy,但是因为girl对象里面的智能指针还托管着boy,boy的引用计数为2,所以释放spBoy时,引用计数减1,boy的引用计数为1;   在释放spGirl,girl的引用计数减1,为零,开始释放girl的内存,因为girl里面还包含有托管boy的智能指针对象,所以也会进行boyFriend的内存释放,boy的引用计数减1,为零,接着开始释放boy的内存。最终所有的内存都释放了。   五、weak_ptr   weak_ptr 设计的目的是为配合 shared_ptr 而引入的一种智能指针来协助 shared_ptr 工作, 它只可以从一个 shared_ptr 或另一个 weak_ptr 对象构造, 它的构造和析构不会引起引用记数的增加或减少。 同时weak_ptr 没有重载*和->但可以使用 lock 获得一个可用的 shared_ptr 对象。   弱指针的使用;   weak_ptr wpGirl_1; // 定义空的弱指针   weak_ptr wpGirl_2(spGirl); // 使用共享指针构造   wpGirl_1 = spGirl; // 允许共享指针赋值给弱指针   弱指针也可以获得引用计数;   wpGirl_1.use_count()   弱指针不支持 * 和 -> 对指针的访问;
字符数组的指针如何定义_指针指向数组
字符数组的指针如何定义_指针指向数组   在必要的使用可以转换成共享指针 lock();   使用代码:   当然这只是一些使用上的小例子,具体用法如下:   请看Boy类   
字符数组的指针如何定义_指针指向数组
字符数组的指针如何定义_指针指向数组   在类中使用弱指针接管共享指针,在需要使用时就转换成共享指针去使用即可!   自此问题完美解决!   expired函数的用法   应评论区某位朋友的要求,现在加上weak_ptr指针的expired函数的用法!   expired:判断当前weak_ptr智能指针是否还有托管的对象,有则返回false,无则返回true   如果返回true,等价于 use_count() == 0,即已经没有托管的对象了;当然,可能还有析构函数进行释放内存,但此对象的析构已经临近(或可能已发生)。   示例   演示如何用 expired 检查指针的合法性。   在网上找了一段代码,加上自己的注释理解   
字符数组的指针如何定义_指针指向数组
字符数组的指针如何定义_指针指向数组   在 { } 中,gw的生命周期还在,他还在托管着make_shared赋值的指针,所以调用f()函数时打印”gw is valid\n”;   当执行完 { } 后,gw的生命周期已经结束,已经调用析构函数释放make_shared指针内存,gw已经没有在托管任何指针了,调用expired()函数返回true,所以打印”gw is expired\n”;   六、智能指针的使用陷阱   不要把一个原生指针给多个智能指针管理;   int *x = new int(10);   unique_ptr< int > up1(x);   unique_ptr< int > up2(x);   // 警告! 以上代码使up1 up2指向同一个内存,非常危险   或以下形式:   up1.reset(x);   up2.reset(x);   记得使用u.release()的返回值;   在调用u.release()时是不会释放u所指的内存的,这时返回值就是对这块内存的唯一索引,如果没有使用这个返回值释放内存或是保存起来,这块内存就泄漏了.   禁止delete 智能指针get 函数返回的指针;   如果我们主动释放掉get 函数获得的指针,那么智能 指针内部的指针就变成野指针了,析构时造成重复释放,带来严重后果!   禁止用任何类型智能指针get 函数返回的指针去初始化另外一个智能指针!   shared_ptr< int > sp1(new int(10));   // 一个典型的错误用法 shared_ptr< int > sp4(sp1.get());   七、总结   智能指针虽然使用起来很方便,但是要注意使用智能指针的一些陷阱,否则会造成严重的内存报错或者内存泄露等问题!

2024最新激活全家桶教程,稳定运行到2099年,请移步至置顶文章:https://sigusoft.com/99576.html

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请联系我们举报,一经查实,本站将立刻删除。 文章由激活谷谷主-小谷整理,转载请注明出处:https://sigusoft.com/25523.html

(0)
上一篇 2024年 9月 13日 下午8:53
下一篇 2024年 9月 13日 下午9:02

相关推荐

关注微信