Android智能指針

C++ RAII對象

RAII的全稱是Resource Acquisition Is Initialization,即“資源獲取就是初始化”。RAII的做法是使用一個對象,在其構造時獲取對應的資源,在對象生命期內控制對資源的訪問,使之始終保持有效,最後在對象析構的時候,釋放構造時獲取的資源。把資源放到對象裏面,便可依賴C++的構造函數和析構函數機制,確保對資源的持有和釋放。

智能指針便是屬於RAII的一種,智能指針是一個用於管理資源的對象,其使用引用計數技術。在智能指針對象構造時,增加它所引用對象的的引用計數,在其析構時,減少它所持有對象的引用計數。當引用對象的引用計數爲0時,便釋放引用對象。
引用計數存放在引用對象中,在智能指針對象構造時,需要將待引用對象傳入到智能指針對象的構造函數中,在構造函數會對引用對象的引用計數加1,當智能指針對象析構時,就將其所引用對象的引用計數減1。

Android內置的智能指針包含三種:輕量級指針、強指針、弱指針。

輕量級指針

輕量級指針通過簡單的引用計數技術來維護對象的生命週期,下文從代碼角度分析下輕量級指針的實現原理。

LightRefBase 類

// code path: /system/core/include/utils/lightRefBase.h
template <class T>
class LightRefBase
{
public:
    inline LightRefBase() : mCount(0) { }
    inline void incStrong(__attribute__((unused)) const void* id) const {
        mCount.fetch_add(1, std::memory_order_relaxed);
    }
    inline void decStrong(__attribute__((unused)) const void* id) const {
        if (mCount.fetch_sub(1, std::memory_order_release) == 1) {
            std::atomic_thread_fence(std::memory_order_acquire);
            delete static_cast<const T*>(this);
        }
    }
    //! DEBUGGING ONLY: Get current strong ref count.
    inline int32_t getStrongCount() const {
        return mCount.load(std::memory_order_relaxed);
    }

    typedef LightRefBase<T> basetype;

protected:
    inline ~LightRefBase() { }

private:
    friend class ReferenceMover;
    inline static void renameRefs(size_t /*n*/, const ReferenceRenamer& /*renamer*/) { }
    inline static void renameRefId(T* /*ref*/, const void* /*old_id*/ , const void* /*new_id*/) { }

private:
    mutable std::atomic<int32_t> mCount;	// 對象的引用計數
};

任何需要使用輕量級指針的類對象都必須要繼承 LightRefBase 類。LightRefBase是一個模板類,其中模板參數T表示對象的實際類型,它必須是繼承了 LightRefBase 類的。其成員變量mCount用來描述對象的的引用計數值,提供了兩個public接口 incStrongdecStrong 來增加和減少對象的引用計數值。

PS:在成員函數decStrong中,當對象的引用計數值爲1時,其減少之後就會變成0,就表示需要需要釋放這個對象所佔用的內存了。

輕量級指針的實現類 sp

我們有了輕量級指針所指向的對象,那麼這個對象由誰來指向?即誰來調用對象的 incStrongdecStrong 函數?接下來需要真正的輕量級指針的實現類,Android提供的輕量級指針的實現類是 sp ,它也是強指針的實現類,這裏僅關注它與輕量級指針相關的實現。

template<typename T>
class sp {
public:
    inline sp() : m_ptr(nullptr) { }

    sp(T* other);  // NOLINT(implicit)
    sp(const sp<T>& other);
    sp(sp<T>&& other);
    template<typename U> sp(U* other);  // NOLINT(implicit)
    template<typename U> sp(const sp<U>& other);  // NOLINT(implicit)
    template<typename U> sp(sp<U>&& other);  // NOLINT(implicit)

    ~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; }
    inline explicit operator bool () const { return m_ptr != nullptr; }

    // 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 類也是一個模板類,模板參數T表示所引用對象的實際類型,該類型必須繼承自 LightRefBase 類。sp 也是強指針的實現類,這裏僅關注其對於輕量級指針的實現:

T* m_prt;	//該成員變量用於指向所引用的對象,該對象必須繼承自 LightRefBase

template<typename T>
sp<T>::sp(T* other)
        : m_ptr(other) {
    if (other)
        other->incStrong(this);
}

template<typename T>
sp<T>::sp(const sp<T>& other)
        : m_ptr(other.m_ptr) {
    if (m_ptr)
        m_ptr->incStrong(this);
}

template<typename T>
sp<T>& sp<T>::operator =(T* other) {
    T* oldPtr(*const_cast<T* volatile*>(&m_ptr));
    if (other) other->incStrong(this);
    if (oldPtr) oldPtr->decStrong(this);
    if (oldPtr != *const_cast<T* volatile*>(&m_ptr)) sp_report_race();
    m_ptr = other;
    return *this;
}

template<typename T>
sp<T>& sp<T>::operator =(const sp<T>& other) {
    // Force m_ptr to be read twice, to heuristically check for data races.
    T* oldPtr(*const_cast<T* volatile*>(&m_ptr));
    T* otherPtr(other.m_ptr);
    if (otherPtr) otherPtr->incStrong(this);
    if (oldPtr) oldPtr->decStrong(this);
    if (oldPtr != *const_cast<T* volatile*>(&m_ptr)) sp_report_race();
    m_ptr = otherPtr;
    return *this;
}

template<typename T>
sp<T>::~sp() {
    if (m_ptr)
        m_ptr->decStrong(this);
}

sp 類和輕量級相關的就是它的構造函數、賦值操作符以及、析構函數。構造函數和析構函數的邏輯非常簡單,構造時將所引用對象的引用計數加1,析構時將所引用對象的引用計數減1,都是調用 LightRefBase 的接口。
它的賦值操作符的邏輯就會稍有點複雜,再次先回憶下智能指針的原理:當引用對象有智能指針指向它時,就會給它的引用計數加1;當指向了所引用對象的智能指針不在指向改對象時,它的引用計數就會減1。賦值函數的邏輯同理,由於智能指針指向的新的對象,就會增加新對象的引用計數,而減少舊對象的引用計數。

UML類圖

輕量級指針類圖

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章