Android 智能指针详解 -- sp

概述:

Android中定义了两种智能指针类型,一种是强指针sp(strong pointer),另外一种是弱指针(weak pointer)。其实称之为强引用和弱引用更合适一些。强指针与一般意义的智能指针概念相同,通过引用计数来记录有多少使用者在使用一个对象,如果所有使用者都放弃了对该对象的引用,则该对象将被自动销毁。
弱指针也指向一个对象,但是弱指针仅仅记录该对象的地址,不能通过弱指针来访问该对象,也就是说不能通过弱智真来调用对象的成员函数或访问对象的成员变量。要想访问弱指针所指向的对象,需首先通过wp类所提供的promote()方法将弱指针升级为强指针。弱指针所指向的对象是有可能在其它地方被销毁的,如果对象已经被销毁,wp的promote()方法将返回空指针,这样就能避免出现地址访问错的情况。

 

这些都通过source code来解释。

本文总结基于Android 7.0

 

source code:system/core/include/utils/StrongPointer.h(其他的版本路径应该都在framwork目录下)

template<typename T>
class sp {
public:
    inline sp() : m_ptr(0) { }
 
    sp(T* other);
    sp(const sp<T>& other);
    sp(sp<T>&& other);
    template<typename U> sp(U* other);
    template<typename U> sp(const sp<U>& other);
    template<typename U> sp(sp<U>&& other);
 
    ~sp();
 
    // Assignment
 
    sp& operator = (T* other);
    sp& operator = (const sp<T>& other);
    sp& operator = (sp<T>&& other);
 
    template<typename U> sp& operator = (const sp<U>& other);
    template<typename U> sp& operator = (sp<U>&& other);
    template<typename U> sp& operator = (U* other);
 
    //! Special optimization for use by ProcessState (and nobody else).
    void force_set(T* other);
 
    // Reset
 
    void clear();
 
    // Accessors
 
    inline  T&      operator* () const  { return *m_ptr; }
    inline  T*      operator-> () const { return m_ptr;  }
    inline  T*      get() const         { return m_ptr; }
 
    // Operators
 
    COMPARE(==)
    COMPARE(!=)
    COMPARE(>)
    COMPARE(<)
    COMPARE(<=)
    COMPARE(>=)
 
private:    
    template<typename Y> friend class sp;
    template<typename Y> friend class wp;
    void set_pointer(T* ptr);
    T* m_ptr;
};
首先看下sp的定义,分几部分:

1、这是个模板类

对于模板,详细看 C++模板详解

2、类型T、U是指针变量的类型

3、有7个构造函数、6个“=”的重载

4、宏COMPARE的6个函数都是运算符的重载

5、m_ptr就是指针变量,后面的所有操作都是通过这个来

 

来看下sp构造函数的实现:

template<typename T>
sp<T>::sp(T* other)
        : m_ptr(other) {
    if (other) //如果构造函数形参的指针不为null,该指针的计数加1,这个后面解释
        other->incStrong(this);
}
 
template<typename T>
sp<T>::sp(const sp<T>& other)//实参为sp<T>类型的对象,这里形参为引用
        : m_ptr(other.m_ptr) {
    if (m_ptr)
        m_ptr->incStrong(this);
}
 
template<typename T>
sp<T>::sp(sp<T>&& other) //这里C++11中的移动构造函数,会在另一篇博文中详解
        : m_ptr(other.m_ptr) {
    other.m_ptr = nullptr;
}
 
template<typename T> template<typename U>
sp<T>::sp(U* other) //这里大部分是子类往父类转换
        : m_ptr(other) {
    if (other)
        ((T*) other)->incStrong(this);
}
 
template<typename T> template<typename U>
sp<T>::sp(const sp<U>& other)
        : m_ptr(other.m_ptr) {
    if (m_ptr)
        m_ptr->incStrong(this);
}
 
template<typename T> template<typename U>
sp<T>::sp(sp<U>&& other)//同样是C++11特性移动构造函数,后面详解
        : m_ptr(other.m_ptr) {
    other.m_ptr = nullptr;
}
sp构造就是为了给指针T或者指针U多一个引用的地方,所以,在构造的时候必须做两件事情:

1、初始化sp中关键的指针m_ptr,也就是实参的指针

2、m_ptr也就是实参指针必须要调用incStrong()进行计数加1

构造的时候原来sp的引用为0,无需对m_ptr进行decStrong(),但下面的运算符重载就不是这样了。

对于incStrong 和 decStrong暂时理解为指针m_ptr的计数加1和减1,后面会详解。

 

再来看下sp中的赋值运算符重载:

template<typename T>
sp<T>& sp<T>::operator =(const sp<T>& other) {
    T* otherPtr(other.m_ptr);
    if (otherPtr)
        otherPtr->incStrong(this);//参数other中的指针m_ptr要多一个引用了,调用incStrong()
    if (m_ptr)
        m_ptr->decStrong(this);//当前的指针需要被other代替,那么目前的指针m_ptr的引用计数需要减1
    m_ptr = otherPtr;
    return *this;
}
 
template<typename T>
sp<T>& sp<T>::operator =(sp<T>&& other) {
    if (m_ptr)
        m_ptr->decStrong(this);//这里是移动赋值,会将other中的m_ptr直接移动给这里的m_ptr,之前要先decStrong
    m_ptr = other.m_ptr;
    other.m_ptr = nullptr;
    return *this;
}
 
template<typename T>
sp<T>& sp<T>::operator =(T* other) {
    if (other)
        other->incStrong(this);//直接指针赋值就更简单了
    if (m_ptr)
        m_ptr->decStrong(this);
    m_ptr = other;
    return *this;
}
 
template<typename T> template<typename U>
sp<T>& sp<T>::operator =(const sp<U>& other) {//考虑到子类向父类赋值
    T* otherPtr(other.m_ptr);
    if (otherPtr)
        otherPtr->incStrong(this);
    if (m_ptr)
        m_ptr->decStrong(this);
    m_ptr = otherPtr;
    return *this;
}
 
template<typename T> template<typename U>
sp<T>& sp<T>::operator =(sp<U>&& other) {
    if (m_ptr)
        m_ptr->decStrong(this);
    m_ptr = other.m_ptr;
    other.m_ptr = nullptr;
    return *this;
}
 
template<typename T> template<typename U>
sp<T>& sp<T>::operator =(U* other) {
    if (other)
        ((T*) other)->incStrong(this);
    if (m_ptr)
        m_ptr->decStrong(this);
    m_ptr = other;
    return *this;
}
6个赋值函数,或者叫6个 “=” 的重载中注意的是原来的decStrong 和新的指针的incStrong。

 

 

再来看下sp的析构函数:

template<typename T>
sp<T>::~sp() {
    if (m_ptr)
        m_ptr->decStrong(this);
}
当sp不在使用的时候,指针T *m_ptr需要将计数减1。

 

再来看下三个获取指针的方式:

    inline  T&      operator* () const  { return *m_ptr; }
    inline  T*      operator-> () const { return m_ptr;  }
    inline  T*      get() const         { return m_ptr; }
例如:

class Test {
public:
    Test() {}
    ~Test() {}
    void test() { cout << "just for test ...\n";}
};
 
main () {
    sp<Test> hehe(new Test()); //构造的时候可以直接传入指针
    hehe->test(); //通过 -> 指向指针m_ptr,直接调用Test的test函数
    *hehe.test(); //通过 * 找到对应的Test 引用
    Test *t = hehe.get(); //sp 中get函数就是为了获取指针m_ptr
    t->test();
}
 

再来看下其他的函数:

 

template<typename T>
void sp<T>::force_set(T* other) {//特殊需要用,一般不会用到
    other->forceIncStrong(this);
    m_ptr = other;
}
 
template<typename T>
void sp<T>::clear() {//做sp rest功能使用,会将指针的计数减1,指针置为空指针,注意C++11上用nullptr
    if (m_ptr) {
        m_ptr->decStrong(this);
        m_ptr = 0;
    }
}
 
template<typename T>
void sp<T>::set_pointer(T* ptr) {//这个是private函数,wp在做promote的时候会使用到,wp通过friend方式调用到这里。
    m_ptr = ptr;
}
 

 

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

flybirding10011

谢谢支持啊999

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值