3.9 C++高级编程_Android弱指针的引入

上一节简单介绍了安卓的轻量级指针,它的优点就是代码简单,使用方便

但是,它也有一个缺点,没有办法处理一些复杂的情况

比如说有两个智能指针 A 和 B,它们互相引用,即A引用到B,B也引用到A。

那么我们将无法释放A和B,因为A引用了B,B的引用计数会加1,同理A的引用计数也会加1。

这样,当我们尝试释放A或B的时候,引用计数永远也不会为0,即A和B永远也不会释放。

修改代码,在Person类中增加两个sp<Person>类成员,father和son,并且增加两个成员函数setSon和setFather。

修改测试函数,创建两个sp<Person> 对象father 和 son,它们就相当于开头描述的A和B。

然后分别调用 setSon和 setFather函数,让他们互相引用。

 

在main函数中调用测试函数。

 

编译测试,发现只调用了Person类的构造函数,对应的析构函数没有调用,也就是说father和son在程序执行完毕后,没有释放。

修改test_func函数,让它们没有相互引用。

编译测试,此时Person类的析构函数会被调用。

先来分析一下构造函数和析构函数被调用的过程。

  • 构造时:如果对象里含有其他对象成员,那么构造时先构造所包含的其他对象成员,再构造对象本身;
  • 析构时:顺序与构造函数相反。

当执行 sp<Person> father = new Person(); 时,实际上有四个构造函数被调用:

  1. Person对象里的father先被构造;
  2. Person对象里的Son被构造;
  3. Person对象本身被构造;
  4. father对象本身被构造;

由于没有传入参数,所以会调用的构造函数分别是:

  1. Person对象里的father先被构造;—— inline sp() : m_ptr(0) { }
  2. Person对象里的Son被构造; —— inline sp() : m_ptr(0) { }
  3. Person对象本身被构造; —— Person()
  4. father对象本身被构造;—— sp<T>::sp(T* other)

其中,inline sp() : m_ptr(0) { } 没有做什么操作,只是简单的初始化一下私有成员m_ptr;Person()会输出一个调试信息;而sp<T>::sp(T* other)则会调用 incStrong函数,将引用计数值mCount 加1。

最终,引用计数值mCount为1。

 

 

 

同理,当执行 sp<Person> son = new Person(); 后,son的引用计数值也为1。

再来分析一下 father->setSon(son);

会导致Person类中setSon函数被调用,由于sp类中对“=”进行了重定向,所以 this->son = other; 实际上执行的是 sp& operator = (const sp<T>& other);

在重载函数中会将son的引用计数加1,之后son的引用计数就会等于2。

 

即 father->setSon(son); 执行完以后,son对应的Person的引用计数为2。

同理,son->setFather(father); 执行完以后,father对应的Person的引用计数为2。

最后,当函数执行完要退出时,由于son和father对应的Person的引用计数没有减为0,所以不会调用对应的Person类的析构函数。

问题的实质在于,father 引用了 son,father 可以决定 son 的生死,同理,son 也可以决定 father 的生死。

要想杀死 father,必须先杀死father的引用son;要想杀死son,必须先杀死son的引用father。这就变成了一个死锁,最终导致谁都死不了。

像这种A引用B,并且A可以决定B的生死的引用,称为强引用,或者强指针。

对应的,A引用B,但是A不可以决定B的生死的引用,称为弱引用,或者弱指针。

本节问题的根源就是使用的是强引用,如果使用的是弱引用,那么就不会有这个问题。

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值