C++ make_shared智能指针的使用

​ C++使用模板函数 std::make_shared 可以返回一个指定类型的 std::shared_ptr

1、为何使用动态内存

如果事先知道所需内存空间,使用静态内存是最简单的解决方案。

但是,在程序设计的过程中,往往会遇到需要开辟一个未知大小的内存空间,该空间根据程序所需发生大小的变化,此空间称为动态内存。

程序设计中使用动态内存的原因可能如下:

  • 程序不知道自己需要多少对象;
  • 程序不知道所需对象的准确类型;
  • 程序需要在多个对象之间共享数据。

2、make_shared用法

make_shared在动态内存中分配一个对象并初始化它, 返回指向此对象的shared_ptr,与智能指针一样,make_shared定义在头文件memory中;

当要用make_shared时,必须指定想要创建的对象类型,定义方式与模板类相同,在函数名之后跟一个尖括号,在其中给出类型;

make_shared<int>p3 = make_shared<int>(42)
//一般采用auto定义一个对象来保存make_shared的结果
auto p1 = make_shared<int>(42);    

3、shared_ptr用法

可以指向特定类型的对象,用于自动释放所指的对象。

(1)优点
  • 效率更高shared_ptr 需要维护引用计数的信息,

    • 强引用, 用来记录当前有多少个存活的 shared_ptrs 正持有该对象. 共享的对象会在最后一个强引用离开的时候销毁( 也可能释放)
    • 弱引用, 用来记录当前有多少个正在观察该对象的 weak_ptrs. 当最后一个弱引用离开的时候, 共享的内部信息控制块会被销毁和释放 (共享的对象也会被释放, 如果还没有释放的话)

    内存分配的动作, 可以一次性完成.

    这减少了内存分配的次数, 而内存分配是代价很高的操作

  • 异常安全

(2)缺点
  • 构造函数是protected或private时,无法使用 make_shared

  • 对象的内存可能无法及时回收

    weak_ptr 会保持控制块(强引用, 以及弱引用的信息)的生命周期, 而因此连带着保持了对象分配的内存, 只有最后一个 weak_ptr 离开作用域时, 内存才会被释放. 原本强引用减为 0 时就可以释放的内存, 现在变为了强引用, 若引用都减为 0 时才能释放, 意外的延迟了内存释放的时间。

  • 1
    点赞
  • 12
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
C++智能指针 ⼀ ⼀. 智能指针 智能指针C++ 中,我们申请内存⼀般使⽤ new,释放内存时使⽤ delete,但是有时候我们可能由于疏忽会忘记 delete,或者当程序有多个 出⼝时,也会容易有 new 没有 delete,这样就产⽣了内存泄漏,如果你的程序是⼀个需要长期运⾏的服务器程序,可能运⾏着⼏天突然程 序就崩溃了,原因也不好定位,所以为了⽅便内存管理C++ 引⼊了智能指针智能指针的优点在于能够帮助程序员⾃动释放我们 new 出 来的堆内存。 C++ 标准库有四种智能指针:auto_ptr,unique_ptr,shared_ptr,weak_ptr(auto_ptr 是 C++98 标准的,其余都是 C++11 标准推出的,auto_ptr 现在已经不再使⽤了),C++11 这三种智能指针都是类模板。 ⼆ ⼆. shared_ptr (⼀)概述 (⼀)概述 shared_ptr 是⼀个共享式指针,所有的 shared_ptr 共享对指向内存的所有权,不是被⼀个 shared_ptr 拥有,⽽是多个 shared_ptr 之间互相协作。 (⼆)⼯作原理 (⼆)⼯作原理 引⽤计数,use_count 为 0 时就释放对象空间。 (三)初始化 (三)初始化 如果是定义了⼀个智能指针却不初始化,shared_ptr<int> p1,代表定义了⼀个指向 int 类型对象的智能指针但是⽬前指向为 empty。推荐使⽤ make_shared 函数来初始化 shared_ptr,它是标准库的函数模板,安全,⾼效地分配和使⽤ shared_ptr。 shared_ptr<int> pint = make_shared<int>(100); shared_ptr<string> pstr = make_shared<string>(5,'a'); 也可以使⽤直接初始化的⽅式 shared_ptr<int> pint(new int(100)) 来创建⼀个 shared_ptr 并初始化,但是由于 shared_ptr 定义 的构造函数是 explicit 的,因此不能使⽤ shared_ptr<int> pint = new int(100) 来创建⼀个 shared_ptr 并初始化,因为这种⽅式隐式要 求将⼀个普通的 int * 转换为 shared_ptr<int>。 (四)常⽤操作 (四)常⽤操作 1. use_count 返回多少个智能指针指向该对象,主要⽤于调试。 2. unique 判断该智能指针是否独占该内存,如果该智能指针不指向任何对象,判断 unique 的时候也是假。 3. reset 不带参数时:放弃指针对对象的掌管权,重置为 nullptr 带参数时:参数⼀般是⼀个 new 的空间,相当于放弃指针对当前对象的掌管权,然后将指针指向 new 出来的空间。 4. * 解引⽤,可以获取指针指向的对象。 5. get 获取指针指针⾥保存的裸指针,⼀般⽤于⼀些接⼝需要使⽤到 C 语⾔指针的情况。 6. swap 交换两个智能指针所指的对象。 7. =nullptr 该智能指针指向 nullptr,代表解除对该对象的掌握权,引⽤计数将会减1,如果此时该内存空间的引⽤计数变为0,会同时释放该内存。 8. 指定删除器以及删除数组问题 指定删除器以及删除数组问题 智能指针能在⼀定时机帮我们删除所指向的对象,使⽤ delete 作为默认的资源析构⽅式,我们也可以指定⾃⼰的删除器取代系统提供的默 认删除器,当智能指针需要删除所指向的对象时,编译器就会调⽤我们提供的删除器。 shared_ptr 指定删除器的⽅法⽐较简单,⼀般只需要在参数中添加具体的删除器函数即可。如果提供了删除器,那么就需要⼿动删除资 源,否则会造成内存泄漏。删除器函数可以是函数,lambda 表达式,重载了 operator() 的类等。 还可以使⽤ default_delete 来做删除器,default_delete 是标准库⾥的⼀个模板类。如:shared_ptr<A> p3(new A[10], default_delete<A[]>()),这样就知道我们使⽤智能指针指向了⼀个对象数组,这样就可以正确释放了。 其实,使⽤ shared_ptr 指向对象数组不需要通过删除器的⽅式,只需要在定义 shared_ptr 时指为数组类型即可,如:shared_ptr<A[]> p4(new A[10])。 额外说明:就算是两个 shared_ptr 指定了不同的删除器,只要他们指向的对象类型相同,那么这两个 shared_ptr 也是同⼀个类型,可以 放到同⼀个容器去,vector<shared_ptr<int>> pvec{p1,p2}。 三 三
C++智能指针shared_ptr⽤法详解 C++智能指针shared_ptr⽤法详解 shared_ptr是C++11⾥的新特性,其包装了new操作符在堆上分配的动态对象。如: shared_ptr<int> sp1(new int(100)); //相当于 //int *sp1=new int(100); //auto sp1=make_shared<int>(100); 它与普通指针相⽐,最⼤的不同点就是shared_ptr是⼀个类,当对象⽣命周期结束时,会⾃动调⽤其析构函数,释放内存。⽽不再需要程 序员显⽰地调⽤delete关键字。 同时,shared_ptr重载了"*"和"->"操作符以模仿原始指针的⾏为,并且提供了显⽰bool类型转换以判断指针的有效性。 shared_ptr<int> sp1(new int(100)); assert(sp1); *sp1=200; shared_ptr<string> sp2(new string("Hello")); assert(sp2->size()==5); 我们还可以使⽤shared_ptr的成员函数get()获取原始指针 shared_ptr<int> sp1(new int(100)); int *Int_ptr=sp1.get(); shared_ptr⾥的reset()函数 shared_ptr⾥有个成员函数use_count(),⽤于返回该对象的引⽤计数。 shared_ptr<int> sp1(new int(100)); cout<<"当前计数: "<<sp1.use_count()<<endl; auto sp2=sp1; cout<<"当前计数: "<<sp1.use_count()<<endl; { auto sp3=sp2; cout<<"当前计数: "<<sp1.use_count()<<endl; } cout<<"当前计数: "<<sp1.use_count()<<endl; 当⼀个shared_ptr对象调⽤reset()函数时,它的作⽤时将引⽤计数减⼀,调⽤本⾝的对象的引⽤计数变为0. shared_ptr<int> sp1(new int(100)); cout<<"当前计数: "<<sp1.use_count()<<endl; auto sp2=sp1; cout<<"当前计数: "<<sp1.use_count()<<endl; { auto sp3=sp2; cout<<"当前计数: "<<sp1.use_count()<<endl; } cout<<"当前计数: "<<sp1.use_count()<<endl; sp2.reset();//这⾥换成sp1.reset(),可以发现sp2的计数为1,sp1的计数为0. cout << "sp2当前计数: " << sp2.use_count() << endl; cout << "sp1当前计数: " << sp2.use_count() << endl; 上⾯代码运⾏后,sp2的计数为0,sp1的计数为1。若将sp2.reset()换位sp1.reset(),则sp2的计数为1,sp1的计数为0。 在每次对shared_ptr进⾏拷贝或者赋值的时候,都会使计数加1。 ⼯⼚函数 每次使⽤shared_ptr都需要显⽰的使⽤new关键字创建⼀个对象。固std库提供了⼀个⼯⼚函数make_shared()。 ⽤法: auto sp1=make_shared<int>(100); //相当于 shared_ptr<int> sp1(new int(100)); make_shared是⼀个泛型,<>⾥⾯为数据类型,()对应着new()⾥的东西,其返回值是⼀个shared_ptr类型的变量。 定制删除器 shared_ptr的构造函数可有多个参数,其中有⼀个是shared_ptr(Y *p,D d),第⼀个参数是要被管理的指针,它的含义与其构造函数的参 数相同。⽽第⼆个参数则告诉shared_ptr在析构时不要使⽤delete来操作指针p,⽽要⽤d来操作,即把delete p 换成d(p)。因此,我们 就可以⾃⼰制作⼀个删除器 如:对于传统的struct FILE的C⽂件操作,需要 FILE *fp=fopen("./1.txt","r"); //... //... fclose(fp); 若⽤shared_ptr,则可以这样做: shared_ptr<FILE> fp(fopen("./1.txt","r"), fclose); 离开作⽤域时,shared_ptr会⾃动调⽤fclose()函数关闭⽂件。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值