Understand the implementation of lightweight pointer in Android system

  • 2021-12-21 04:57:15
  • OfStack

Smart pointer source

The performance of raising pointer error conditions often has the following performance conditions:
1. Requested memory space, but forgot to free the memory space occupied by the object pointed to by the pointer.
2. An invalid pointer was used.
Therefore, the smart pointer technology is adopted in the C + + code part of android. Smart pointers use a technology that can automatically compromise object reference counting. To solve the defects of pointers in C + +.
Three types of C + + smart pointers are provided in android system, which are lightweight smart pointers, strong pointers and weak pointers.
The following mainly analyzes the realization principle of lightweight pointer.

Lightweight pointer

Lightweight pointers maintain the life cycle of objects by using simple reference counting classes. If objects of a class support lightweight pointers, it must inherit from LightRefBase class, because this LightRefBase class provides a simple reference counter.

LightRefBase class definition

The following source code is mainly analyzed according to the source code of android5.0. The LightRefBase class is defined in the file\ frameworks\ rs\ cpp\ util\ RefBase. h in the android system.
The LightRefBase class is also a template class. The template parameter T represents the actual type of the object, which must inherit from the class LightRefBase.


// Template class 
template <class T>
class LightRefBase
{
public:
    // Common inline function 
    inline LightRefBase() : mCount(0) { }
    inline void incStrong(__attribute__((unused)) const void* id) const {
        __sync_fetch_and_add(&mCount, 1);
    }
    inline void decStrong(__attribute__((unused)) const void* id) const {
        if (__sync_fetch_and_sub(&mCount, 1) == 1) {
            delete static_cast<const T*>(this);
        }
    }
    //! DEBUGGING ONLY: Get current strong ref count.
    inline int32_t getStrongCount() const {
        return mCount;
    }

    typedef LightRefBase<T> basetype;

protected:
    // Inline fictional function 
    inline ~LightRefBase() { }

private:
    friend class ReferenceMover;
    inline static void moveReferences(void*, void const*, size_t,
            const ReferenceConverterBase&) { }

private:
    mutable volatile int32_t mCount;
};



The above LightRefBase class definition involves several knowledge points:

1. Three access rights types of C + +: public, protected and private.

public: Can be accessed by any entity.
protected: Only subclasses and member functions of this class are allowed to access.
private: Only member functions of this class are allowed to access.

2. inline inline function in C + +

In Part 1 of Functions, a function that contains the inline keyword is represented as an inline function. Inline functions are mainly used to solve the problem that some frequently called small functions consume a lot of stack space (stack memory).
The use of inline is limited. inline is only suitable for the use of simple code in the body, and cannot contain complex structure control statements such as while and switch, and the inline function itself cannot be a direct recursive function (recursive function: it also calls its own function internally).

3. friend Friend Function in C + +

The friend mechanism in C + + allows non-public members of a class to be accessed by a class or function. Friends are divided into three types: ordinary non-class member functions as friends, class member functions as friends, and class as friends.
Friend functions are non-member functions that can directly access private members of a class. It is an ordinary function defined outside the class. It does not belong to any class, but it needs to be declared in the definition of the class. When declaring, you only need to add the keyword friend before the name of your friend.

4. mutable Keyword in C + +

mutable was set up to break through the limitations of const. Variables decorated with mutable will always be in a mutable state, even in an const function.

5. template class template in C + +

A class template (also known as a generic class or a class-generated class) allows the user to define a schema for the class. Make some data members in the class, write the number of member functions, and return values of some member functions, and take random types (including those defined in advance by the system and by users themselves).
Application scenario of class template: Multiple classes have common operations, but different data types.

Implementation Class of LightRefBase

The implementation class for the lightweight LightRefBase class is the wp class, which is also in the file\ frameworks\ rs\ cpp\ util\ RefBase. h. wp is also a template class, and the template parameter T represents the actual type of the object, which must inherit from the LightRefBase class. Since the wp class is also an implementation class for strong pointers, we only need to analyze the implementation part of the wp class for lightweight pointers.


// Template class 
template <typename T>
class wp
{
public:
    typedef typename RefBase::weakref_type weakref_type;
    // Constructors required for lightweight pointers 
    inline wp() : m_ptr(0) { }

    wp(T* other);
    wp(const wp<T>& other);
    wp(const sp<T>& other);
    template<typename U> wp(U* other);
    template<typename U> wp(const sp<U>& other);
    template<typename U> wp(const wp<U>& other);
    // Fictitious functions needed by lightweight pointers 
    ~wp();

    // Assignment

    wp& operator = (T* other);
    wp& operator = (const wp<T>& other);
    wp& operator = (const sp<T>& other);

    template<typename U> wp& operator = (U* other);
    template<typename U> wp& operator = (const wp<U>& other);
    template<typename U> wp& operator = (const sp<U>& other);

    void set_object_and_refs(T* other, weakref_type* refs);

    // promotion to sp

    sp<T> promote() const;

    // Reset

    void clear();

    // Accessors

    inline  weakref_type* get_refs() const { return m_refs; }

    inline  T* unsafe_get() const { return m_ptr; }

    // Operators

    COMPARE_WEAK(==)
    COMPARE_WEAK(!=)
    COMPARE_WEAK(>)
    COMPARE_WEAK(<)
    COMPARE_WEAK(<=)
    COMPARE_WEAK(>=)

    inline bool operator == (const wp<T>& o) const {
        return (m_ptr == o.m_ptr) && (m_refs == o.m_refs);
    }
    template<typename U>
    inline bool operator == (const wp<U>& o) const {
        return m_ptr == o.m_ptr;
    }

    inline bool operator > (const wp<T>& o) const {
        return (m_ptr == o.m_ptr) ? (m_refs > o.m_refs) : (m_ptr > o.m_ptr);
    }
    template<typename U>
    inline bool operator > (const wp<U>& o) const {
        return (m_ptr == o.m_ptr) ? (m_refs > o.m_refs) : (m_ptr > o.m_ptr);
    }

    inline bool operator < (const wp<T>& o) const {
        return (m_ptr == o.m_ptr) ? (m_refs < o.m_refs) : (m_ptr < o.m_ptr);
    }
    template<typename U>
    inline bool operator < (const wp<U>& o) const {
        return (m_ptr == o.m_ptr) ? (m_refs < o.m_refs) : (m_ptr < o.m_ptr);
    }
                         inline bool operator != (const wp<T>& o) const { return m_refs != o.m_refs; }
    template<typename U> inline bool operator != (const wp<U>& o) const { return !operator == (o); }
                         inline bool operator <= (const wp<T>& o) const { return !operator > (o); }
    template<typename U> inline bool operator <= (const wp<U>& o) const { return !operator > (o); }
                         inline bool operator >= (const wp<T>& o) const { return !operator < (o); }
    template<typename U> inline bool operator >= (const wp<U>& o) const { return !operator < (o); }

private:
    template<typename Y> friend class sp;
    template<typename Y> friend class wp;
    // Variables used by lightweight pointers m_ptr
    T*              m_ptr;
    weakref_type*   m_refs;
};

Summarize

Through the previous concept and system source code functional principle analysis, if we want to use lightweight pointers, then we should include header files and adopt the way of inheriting LightRefBase classes, then we can use the function of lightweight pointers.


Related articles: