C++入门到精通-第五章-5-2&5-3智能指针shared_ptr

三、shared_ptr基础

//错误
shared_ptr pi=new int(200);//错误范例,隐式类型转换,不被允许!
shared_ptr<int> sp(new int(100));//正确,显式类型转换
shared_ptr<int>  function(int value)//返回智能指针的函数
{
	return shared_ptr<int>(new int(value));
}
  • 智能指针,不用delete,不能指向裸指针。错误示范:
int *p=new int();
shared_ptr<int> p1(p);//语法正确,但很容易出问题
shared_ptr<int> pp(new int(100));//智能指针的初始化
shared_ptr<int> pp1=make_shared<int>(100);
  • make_shared函数: 标准库里的函数模板,安全,高效的分配shared_ptr;
  • 它可以在动态内存中分配并初始化一个对象,并返回指向此对象的shared_ptr;
shared_ptr<int> p1=make_shared<int>(100);
p1=make_shared<int>(2);
auto p2=make_shared<int>(520);
  1. 上面p1指向了一个新int,int里保存的是2,p1首先释放刚才指向为100的值为0的内存,然后指向新定义的值为2的内存。
  2. 利用auto来定义新变量,写法较简单。

5-3 shared_ptr常用操作,计数,自定义删除器等

(1)shared_ptr引用计数的增加和减少

  • 引用计数的增加
  • 引用计数的减少

(2)shared_ptr指针的常用操作

  • use_count();
  • unique();
  • reset();
  • * 解引用
  • get();
  • swap();
  • =nullptr
  • 智能指针名字和作为判断条件
  • 指定删除器以及数组问题

3.1 shared_ptr引用计数的增加和减少

  • 共享式引用计数,每一个shared_ptr的拷贝都指向相同的内存对象,只有最后一个指向该对象的shared_ptr指针不需要再指向该对象的时候,这个shared_ptr才会去析构所指向的对象。
  • 引用计数的增加:
  1. 在如下情况下,所有指向这个对象的shared_ptr引用计数都会增加;

a) 利用已存在的智能指针初始化另外一个智能指针的;

b) 把智能指针当做实参往函数里传递,引用计数会在函数里增加1,但是函数执行完毕后,会自动再减一;传引用的话则不会引起值增加。

c) 作为函数的返回值,

void fun(shared_ptr<int> temp)//(&temp)传引用就不会增加
{
    return;
}
shared_ptr p1=make_shared<int>(100);
auto p2(p1);
fun(p2);
  • 引用计数的减少:

调试->内存->内存1 调试查看内存内容

  1. 给shared_ptr赋予新值,让其指向一个新对象;内存调试查看最后没有对象指向最初创建的内存时,最初创建的内存被释放。
shared_ptr<int> p1=make_shared<int>(100);
auto p2(p1);//引用计数为2
p2=make_shared<int>(300);//引用计数减一
p1=make_shared<int>(400);//原指向值100的内存被释放,p1重新占用一块内存并指向值400,引用计数为1.
  1. 局部的shared_ptr离开其作用域;
  2. 当一个shared_ptr引用计数从1变为0,它会自动释放自己所管理的对象。

3.2 shared_ptr指针的常用操作

  • use_count();返回多少个智能指针指向某个对象,主要用于调试目的;
shared_ptr<int> m1(new int(100);
auto m2(m1);
cout<<m2.ues_count()<<endl;//输出为2
  • unique();//是否该智能指针独占某个指向的对象,若只有一个指针指向某个对象,则返回true;
  • reset();//复位,
情况一,reset()不带参数
  1. 若某智能指针pi是唯一指向该对象的指针,那么释放pi所指向的对象,并将其置空;
  2. 若pi不是唯一指向该对象的指针,那么不释放pi所指向的对象,但是指向该对象的引用计数会减少1,同时将pi置空
shared_ptr<int> pi(new int(100));
pi.reset();//pi的引用计数变为0,并且pi被置空

shared_ptr<int> pi2(new int(100));
auto pi3(pi2);
pi2.reset();//pi2被置空,pi3的引用计数从2变为1;
情况二,reset()带参数
  1. 若pi是唯一指向该对象的指针,则释放pi指向的对象,让pi指向新对象;
  2. 若pi不是唯一指向该对象的指针,则指向该对象的引用计数减少1,并将pi指向新对象。
shared_ptr<int> pi(new int(100));
pi.reset(int new(1));//释放原来内存,指向新内存
shared_ptr<int> p2(new int(100));
auto p3(p2);
p2.reset(int new(3));//p3的引用计数从2变为1,p2指向值为3的新内存,
情况三,空指针也可以通过reset来重新初始化
shared_ptr<int> p;
p.reset(new int(1));//释放p所指向的对象,让p指向新对象,因为p原来为空,所以等于什么也没有释放,直接指向新对象。
  • *解引用,获得p指向的对象,和指针用法一样
  • get()
  1. p.get():返回p中保存的指针(裸指针),小心使用,如果智能指针释放了所指向的对象,那么返回的裸指针也就变得没有意义。
  2. 考虑到有些函数的参数需要的是一个内置裸指针而不是智能指针,因此需要.get()函数来进行转换,int *p1=p.get()中p1为普通指针,不可被delete;
  • swap()交换两个智能指针指向的对象,但是不常用。示例用法如下
shared_ptr<string> p1(new string("I love you 1"));
shared_ptr<string> p2(new string("I love you 2"));
swap(p1,p2);//p1和p2的内容交换
p1.swap(p2);//

  • ==nullptr
  1. 将所指向的对象,引用计数减一,若引用计数变为0,则释放智能指针指向的对象。
  2. 将智能指针置空。
shared_ptr<string> p1(new string("I love you"));
p1=nullptr;//
  • 智能指针名字作为判断条件
  1. 就是以ps1是否为空作为if的判断条件。
shared_ptr<int> p1(int new(100));
if(p1){cout<<"p1 is not a nullptr";}
  • 指定删除器及数组问题
  1. 指定删除器

a) 一定时机帮我们删除所指向的对象;delete:将运算符号作为默认的资源析构方式。

b) 我们可以指定自己的删除器取代系统提供的默认删除器,当智能指针需要删除所指向的对象时,编译器就会调用我们自己写的删除器;

c) shared_ptr指定删除器方法比较简单,一般只需要在参数中添加具体的删除器函数名即可

void myDelete(int *p)
{
    delete p;
}
int main()
{
    shared_ptr<int> p1(int new(100), myDelete);//自定义删除器的使用方法
    p1.reset();//系统在执行reset时,会进入到myDelte中进行delete
}
  1. 删除器可以是一个lambda表达式
shared_ptr<int> p(int new(100),[](int*p1){delete p1;});
  1. Q:为什么要指定删除器?

a) 有些情况下,默认删除器处理不了,需要我们自己指定删除器。比如shared_ptr管理动态数组。如果不使用指定删除器删除动态数组,则会报错

shared_ptr<int> p(new int[10],[](int *p){
    delete []p;
});
  1. 可用default_delete 来做删除器,是标准库里的模板类
shared_ptr<int> p1(new int[10], default_delete<int[]>());
  1. 其实对于动态数组问题,我们不一定需要自定义删除器,目前C++语法中已经提出了适应性的语法
shared_ptr<int[]> p(new int[10]);//这样动态数组p就可以在析构时全部删除了
p[0]=12;//还可以实现下标操作
p[1]=15;
  1. 指定删除器额外说明

即使指定了额外删除器,两个指针仍然是同一类型。都可以放到vector里

make_shared生成指针,不能指定自定义的删除器,因此如果需要指定自己的删除器,则不能使用make_shared;

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值