Android 智能指針詳解 -- sp

概述:函數

Android中定義了兩種智能指針類型,一種是強指針sp(strong pointer),另一種是弱指針(weak pointer)。其實稱之爲強引用和弱引用更合適一些。強指針與通常意義的智能指針概念相同,經過引用計數來記錄有多少使用者在使用一個對象,若是全部使用者都放棄了對該對象的引用,則該對象將被自動銷燬。
弱指針也指向一個對象,可是弱指針僅僅記錄該對象的地址,不能經過弱指針來訪問該對象,也就是說不能經過弱智真來調用對象的成員函數或訪問對象的成員變量。要想訪問弱指針所指向的對象,需首先經過wp類所提供的promote()方法將弱指針升級爲強指針。弱指針所指向的對象是有可能在其它地方被銷燬的,若是對象已經被銷燬,wp的promote()方法將返回空指針,這樣就能避免出現地址訪問錯的狀況。this

 

這些都經過source code來解釋。指針

本文總結基於Android 7.0rest

 

source code:system/core/include/utils/StrongPointer.h(其餘的版本路徑應該都在framwork目錄下)code

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的定義,分幾部分:對象

一、這是個模板類ci

對於模板,詳細看 C++模板詳解get

二、類型T、U是指針變量的類型io

三、有7個構造函數、6個「=」的重載模板

四、宏COMPARE的6個函數都是運算符的重載

五、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多一個引用的地方,因此,在構造的時候必須作兩件事情:

一、初始化sp中關鍵的指針m_ptr,也就是實參的指針

二、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; }  

相關文章
相關標籤/搜索