Smart pointer in Android

Source: Internet
Author: User
Tags manage wp

Smart pointer in Android



1. Design of smart pointersA very important difference between Java and C ++ is that Java does not have the pointer concept, but does not. Pointers are used internally to hide them, packaging, so that developers do not have to worry about pointers. Let's take a look at a common pointer issue in C ++. 1. Pointer not initialized: Remember to initialize the variable before using it. This problem is well solved. Set the pointer to null by default. 2 The new object is not deleted in time.: The memory space occupied by the object is not recycled in time, so that the system has fewer and fewer available memory space, which may eventually cause memory overflow and crash 3 Wild pointer:Ptr = new Object: an Object is created, and the pointer ptr points to it. After the Object is used, it is deleted. However, if no operation is performed, the ptr is not cleared, in this way, ptr still points to the address of the Object. When the result is used, the ptr is not empty and can be used. However, the Object has been deleted, and the Object on the Object's address may have changed, if you use ptr for access, an unknown error may occur.
How can we solve these problems? This is a good solution for the first problem. If it is set to null during initialization, the second problem can be solved by performing both the new and delete operations. Remember to delete the new object in time. If a smart pointer class SmartPointer is encapsulated here, the SmartPoint class will save the object's memory address and the SmartPoint is a template class. The design is as follows:
Class SmartPointer {// set m_ptr to null during initialization, so that the first problem solves inline SmartPointer (): m_ptr (0) {} private: T * m_ptr; // Save the address of the object}
When m_ptr is set to null during initialization, the first problem is solved. How can we determine whether an object needs to be deleted? When this object is no longer needed, in other words, when no pointer points to this object, we can think that this object is no longer needed. A common solution is to use a counter to record the number of times the object is currently pointed to by a pointer. Each time it is pointed to, the counter of the object is incremented by one, the counter of this object is reduced by one. If the counter value is 0, you can delete this object. Here, a parent class is encapsulated. This parent class represents an object. This object maintains an int type pointer internally and records the number of times the object is pointed:
Class LightRefBase {public: inline LightRefBase (): mCount (0) {} inline void incStrong () const // reference count plus one {android_atomic_inc (& mCount);} inline void decStrong () const // The reference count minus one {if (android_atomic_dec (& mCount) = 1) {delete static_cast
(This); // Delete this object if it is not referenced} private: mutable volatile int32_t mCount; // number of reference counts}
The above is an object class and there are two operations on reference counting, incStrong and decStrong. These two functions are called respectively in the value assignment operation and destructor operation of SmartPointer:
  class SmartPoint{     inline SmartPointer():m_ptr(0){}     ~wp();     SmartPointer& operator = (T* other);private:     T* m_ptr;}
When assigning values to SmartPointer, you must add one to the reference count of the Object. Therefore, you must overload the assignment operator:
& SmartPointer
: Operator = (T * other) {if (other! = Null) {m_ptr = other; // point to this object other-> incStrong (); // other reference count plus one} return * this ;}
During structure analysis, the decStrong of the object is called to reduce the reference count.
::~ Wp () {if (m_ptr) m_ptr-
If another two SmartPointer points to an object, the result is as follows: with this reference count, you don't have to worry about the object being deleted in time, so the second problem is solved. The third problem is also solved.
   2. Implementation of smart pointers in AndroidThere are two types of smart pointers in Android: Strong Pointer (sp) and Weak Pointer (wp ).
   2.1 spCheck sp first. The corresponding file is in the frameworks/native/include/utils/StrongPointer. h file.
     class sp{public:    inline sp() : m_ptr(0) { }    sp(T* other);    sp(const sp
      & other);    template
        sp(U* other);    template
         sp(const sp
        & other);    ~sp();// Assignment    sp& operator = (T* other);    sp& operator = (const sp
          & other);private: template
            friend class sp; template
             friend class wp; void set_pointer(T* ptr); T* m_ptr;};
In this case, if you re-assign values to the assigned SmartPointer, You need to undo the previously pointed object first.
& Sp
: Operator = (T * other) {if (other) other-> incStrong (this); // other object reference count plus if (m_ptr) m_ptr-> decStrong (this); // reduce the reference count of the original object by m_ptr = other; // now m_ptr points to other return * this ;}
We can see that the sp operation is similar to the previous SmartPointer operation, both of which directly add or subtract one to the reference count. This type of pointer is quite understandable. Let's take a look at the wp pointer.
2.2 wpWhy do we need to use weak references when wp weak references already exist? Assume that two more classes are available: CDad and CChild.
struct CDad{     CChild *myChild;}Struct CChild{     CDad *myDad;}
In addition, it is very likely that there will be a situation between them: mutual reference
In this case, the two are in a deadlock state, both of which are in a required State and cannot be released. In this case, a weak reference occurs. Specific Method: CDad uses a strong pointer to reference the CChild object, CChild can only use weak references to point to CDad. When the strong reference count is 0, you must delete yourself no matter whether the weak reference is 0. Once you delete yourself, you can break the deadlock and avoid deadlocks. Let's take a look at the implementation of wp. There are some differences between its implementation and sp, and the relationship between its classes:

Class wp {public: typedef typename RefBase: weakref_type; inline wp (): m_ptr (0) {}// constructor wp (T * other );~ Wp (); // Assignment wp & operator = (T * other); sp
Promote () const; // convert wp to sp function private: T * m_ptr; // point to target object weakref_type * m_refs; // point to weakref_type object };
Note the following points: 1. In addition to m_ptr pointing to the target object, there is also an object pointing to weakref_type. weakref_type is the class used to manage wp. The promote method is implemented by the weakref_impl subclass, you can upgrade wp to sp. The target object in 3 will not be LightRefBase in sp, but its parent class RefBase. This parent class not only needs to process sp, we also need to handle the situation of wp.
Here is an example of the following code:
Class A: public RefBase // This class inherits RefBase {// empty implement} int main () {A * pA = new; // create an object and let the pA point to it {sp spA (pA); // first create an sp and create a wp wpA (spA );} // parse wp and then sp}
Step by step, construct object A, which inherits RefBase, so the RefBase constructor is used.1. Construct a RefBase object
RefBase: RefBase (): mRefs (new weakref_impl (this) // create a weakref_impl type object and assign it to mRefs {}
The RefBase maintains a weakref_impl-type mRefs. weakref_impl inherits the weakref_type class. Let's take a brief look at the weakref_impl class and the weakref_impl constructor.
Class RefBase: volume: public RefBase: volume {public: volatile int32_t mStrong; volatile int32_t mWeak; RefBase * const mBase; volatile int32_t mFlags; volume (RefBase * base ): mStrong (INITIAL_STRONG_VALUE) // strong reference count INITIAL_STRONG_VALUE equals 0x1000000, mWeak (0) // The weak reference count is initialized to 0, and mBase (base) // stores the passed base value, is the target object, mFlags (0) // Save the lifecycle mark, default is Strong, mStrongRefs (NULL), mWeakRefs (NULL), mTrackEnab Led (!! DEBUG_REFS_ENABLED_BY_DEFAULT), mRetain (false) {}// other functions .....}
We can see that the main operation of weakref_impl constructor is to set the initial values for mStrong and mWeak. The RefBase constructor is to create a weakref_impl object and assign it to the mRefs member variable.
2. Create an sp
 sp spA(pA);
View the sp constructor in the StrongPointer. h file.
: Sp (T * other) // other is the pA object created in 1: m_ptr (other) // assign the other value to the m_ptr object {if (other) other-> incStrong (this );}
Call the incStrong function of pA, that is, the incStrong function of RefBase:
Void RefBase: incStrong (const void * id) const {weakref_impl * const refs = mRefs; // mRefs is the weakref_impl object refs-> incWeak (id) created during RefBase construction ); // Let impl's mWeak variable Add a refs-> addStrongRef (id); // for debugging, non-debugging has no specific operation. // The value of c is the value before auto-addition, the mStrong value is initialized to 0x1000000. After the increase, it is 0x1000001 const int32_t c = android_atomic_inc (& refs-> mStrong); if (c! = INITIAL_STRONG_VALUE) {return; // if the value of c is not INITIAL_STRONG_VALUE, return directly} // otherwise, if it is INITIAL_STRONG_VALUE, that is, the first use, perform the following operations // mStrong-INITIAL_STRONG_VALUE, 0x1000001-0x000000 = 1 android_atomic_add (-INITIAL_STRONG_VALUE, & refs-> mStrong); refs-> mBase-> onFirstRef (); // call onFirstRef for initialization at the first reference}
The incWeak function is called:
Void RefBase: weakref_type: incWeak (const void * id) {weakref_impl * const impl = static_cast
(This); impl-> addWeakRef (id); // used for debugging. For non-debugging purposes, there is no specific operation const int32_t c = android_atomic_inc (& impl-> mWeak ); // Add the impl mWeak variable to one. In this case, the mWeak is 0 + 1 = 1}
It can be seen that the sp constructs and calls the incStrong function of RefBase to operate mWeak and mStrong in mRefs, so that the mWeak value is 1 and mStrong is also 1.
3 wp ConstructorWp wpA (spA); the wp class appears here. Its definition is somewhat different from that of sp. As described above, let's look at the wp constructor in the RefBase. h file.
: Wp (const sp
& Other): m_ptr (other. m_ptr) // m_ptr in sp points to the target object and assigns the m_ptr value of sp to m_ptr {if (m_ptr) {m_refs = m_ptr-> createWeak (this) of wp ); // call the createWeak method of pA and save the returned result. m_refs }}
The reference count is not added here. Instead, the createWeak function of the RefBase class is called. This function is in the RefBase. cpp file:
RefBase: weakref_type * RefBase: createWeak (const void * id) const {mRefs-> incWeak (id); // Add mWeak of mRefs to one more, in this case, mWeak is equal to 2 return mRefs; // return mRefs}
The createWeak implementation is to add mWeak of mRefs and return mRefs. In this way, m_refs in wp also points to the mRefs variable, which is 1 for mStrong and 2 for mWeak.
4 wp destructorAt this time, the life of wp is almost over. Check its destructor in the RefBase. h file.
::~ Wp () {if (m_ptr) m_refs-> decWeak (this); // call the decWeak function of m_refs}
Remember that createWeak, m_refs of wp points to the mRefs variable, so it is to call the decWeak function of weakref_type, In the RefBase. cpp File
Void RefBase: weakref_type: decWeak (const void * id) {weakref_impl * const impl = static_cast
(This); impl-> removeWeakRef (id); // used for debugging. No operation is performed without debugging. // retrieve the mWeak value. 2 is saved to c, and subtract one. The value is 1 const int32_t c = android_atomic_dec (& impl-> mWeak); if (c! = 1) return; // because c = 2, return // If c = 1, after one is subtracted, mWeak = 0, it indicates that the weak reference does not point to the target object. You can consider releasing the memory. // OBJECT_LIFETIME_xxxxxx indicates the lifecycle if (impl-> mFlags & OBJECT_LIFETIME_WEAK) = OBJECT_LIFETIME_STRONG) {// This is the regular lifetime case. the object is destroyed // when the last strong reference goes away. since weakref_impl // outlive the object, it is not destroyed in the dtor, and // we'll have to do it here. if (impl-> mStrong = INITIAL_STRONG_VALUE) {// Special case: we never had a strong reference, so we need to // destroy the object now. delete impl-> mBase; // release target object} else {delete impl; // release weakref_impl object} else {/less common case: lifetime is OBJECT_LIFETIME _ {WEAK | FOREVER} impl-> mBase-> onLastWeakRef (id); if (impl-> mFlags & objeclifet_time_mask) = OBJECT_LIFETIME_WEAK) {// this is the OBJECT_LIFETIME_WEAK case. the last weak-reference // is gone, we can destroy the object. delete impl-> mBase ;}}}
After wp analysis, mWeak is reduced to 1, and mStrong is not operated, but is still 1. At this time, neither the target object nor weakref_impl object is actually recycled.
5 sp destructorSelf-sp destructor, in StrongPointer. h file:
::~ Sp () {if (m_ptr) m_ptr-> decStrong (this); // call the desStrong function of the target object}
The target function type here is RefBase. Check the RefBase decStrong function in the RefBase. cpp file:
Void RefBase: decStrong (const void * id) const {weakref_impl * const refs = mRefs; // value refs as the RefBase mRefs value refs-> removeStrongRef (id ); // used for debugging. No operation is performed for non-debugging. // obtain the mStrong value, which is 1 and assigned to c, and change mStrong to 0 const int32_t c = android_atomic_dec (& refs-> mStrong); if (c = 1) {// refs-> mBase-> onlastrongref (id); if (refs-> mFlags & OBJECT_LIFETIME_MASK) = objeclifet_time_strong) {delete this; // Delete the target object} refs-> decWeak (id );}
Here c = 1. If the condition is met, call delete this, that is, the RefBase destructor:
RefBase ::~ RefBase () {if (mRefs-> mStrong = INITIAL_STRONG_VALUE) {// mStrong = 0, not met // we never acquired a strong (and/or weak) reference on this object. delete mRefs;} else {// life-time of this object is extended to WEAK or FOREVER, in // which case weakref_impl doesn't out-live the object and we // can free it now. if (mRefs-> mFlags & OBJECT_LIFETIME_MASK )! = OBJECT_LIFETIME_STRONG) {// enter here // It's possible that the weak count is not 0 if the object // re-acquired a weak reference in its destructor if (mRefs-> mWeak = 0) {// at this time, the mWeak value is 1, not 0, and does not meet the condition delete mRefs ;}}// for debugging purposes, clear this. const_cast
(MRefs) = NULL ;}
We can see that the RefBase destructor does not meet the conditions and does not delete the weakref_impl object. After the RefBase destructor is executed, refs-> decWeak (id) is executed again. Before that, mStrong = 0, mWeak = 1
Void RefBase: weakref_type: decWeak (const void * id) {weakref_impl * const impl = static_cast
(This); impl-> removeWeakRef (id); // used for debugging. No operation is performed without debugging. // retrieve the mWeak value. At this time, 1 is saved to c, and subtract one. The value is 0 const int32_t c = android_atomic_dec (& impl-> mWeak); if (c! = 1) return; // because c = 1, does not match // If c = 1, after one is subtracted, mWeak = 0, it indicates that the weak reference does not point to the target object. You can consider releasing the memory. // OBJECT_LIFETIME_xxxxxx indicates the lifecycle if (impl-> mFlags & OBJECT_LIFETIME_WEAK) = OBJECT_LIFETIME_STRONG) {if (impl-> mStrong = INITIAL_STRONG_VALUE) {delete impl-> mBase; // release target object} else {// enter this condition to judge delete impl; // release the weakref_impl object} else {impl-> mBase-> onLastWeakRef (id); if (impl-> mFlags & OBJECT_LIFETIME_MASK) = OBJECT_LIFETIME_WEAK) {delete impl-> mBase; // release target object }}}

So far, the entire process is over. In RefBase, there is a weakref_impl type mRefs, And the weakref_impl type maintains two important variables: mWeak and mStrong. The RefBase construction is to create a weakref_impl object and assign the value to the mRefs member variable. The main operation of the weakref_impl constructor is to set the initial value for mStrong and mWeak, where mStrong is 0x1000000, when mWeak is 0 sp, mStrong and mWeak are both added, and mStrong and mWeak are both added to the wp structure when mWeak is added, in wp analysis, mWeak minus a RefBase to completely clear the targets and mRefs of the weakref_impl type. If flag is set to 0, that is, when OBJECT_LIFETIME_STRONG is set to 0, the actual target object is deleted. If mWeak is set to 0, the weakref_impl type mRefs is deleted.
3. Other wp knowledge
3.1 wp into spThere is also an important function promote in wp. Its function is to get an sp. Let's look at the following example.
int main(){     A  *pA = new A();     wp wpA(pA);     sp spA = wpA.promote();}
After wp is constructed, mWeak becomes 1, and mStrong is still the initial value 0x100000. Let's look at the promote function. In the RefBase. h file:
: Promote () const {sp
Result; if (m_ptr & m_refs-> attemptIncStrong (& result) {// the key function is the attempIncStrong function result. set_pointer (m_ptr); // assign m_ptr to m_ptr} return result;} of result ;}
The attemptIncStrong function is called here, which is in the RefBase. cpp file:
Bool RefBase: weakref_type: attemptIncStrong (const void * id) {incWeak (id); // mWeak plus one to 2 weakref_impl * const impl = static_cast
(This); // retrieve the mStrong value. Here it is 0x1000000 int32_t curCount = impl-> mStrong; while (curCount> 0 & curCount! = INITIAL_STRONG_VALUE) {if (android_atomic_cmpxchg (curCount, curCount + 1, & impl-> mStrong) = 0) {break;} curCount = impl-> mStrong ;} if (curCount <= 0 | curCount = INITIAL_STRONG_VALUE) {bool allow; // determine whether sp if (curCount = INITIAL_STRONG_VALUE) can be generated from wp) {// Attempting to acquire first strong reference... this is allowed // if the object does NOT have a longer lifetime (meaning the // implement Ation doesn't need to see this), or if the implementation // allows it to happen. allow = (impl-> mFlags & OBJECT_LIFETIME_WEAK )! = OBJECT_LIFETIME_WEAK | impl-> mBase-> onIncStrongAttempted (FIRST_INC_STRONG, id);} else {// Attempting to revive the object... this is allowed // if the object DOES have a longer lifetime (so we can safely // call the object with only a weak ref) and the implementation // allows it to happen. allow = (impl-> mFlags & OBJECT_LIFETIME_WEAK) = OBJECT_LIFETIME_WEAK & impl-> mBase-> onIncStrongAttempted (FIRST_INC_STRONG, id);} if (! Allow) {if not, mWeak minus one and return decWeak (id); return false ;} // If allowed, mStrong plus curCount = android_atomic_inc (& impl-> mStrong); // If the strong reference count has already been incremented by // someone else, the implementor of onIncStrongAttempted () is holding // an unneeded reference. so call onlastrongref () here to remove it. // (No, this is not pretty .) note that we must not do this if we // are in fact acquiring the first reference. if (curCount> 0 & curCount <INITIAL_STRONG_VALUE) {impl-> mBase-> onlastrongref (id) ;}} impl-> addStrongRef (id); // used for debugging, no specific operation if (curCount = INITIAL_STRONG_VALUE) {android_atomic_add (-INITIAL_STRONG_VALUE, & impl-> mStrong); impl-> mBase-> onFirstRef ();} // return success return true ;}
After promote is executed, mStrong and mWeak both add one. At this time, mWeak is 2, mStrong is 1, and an sp object is returned. This object points to the target object pointed to by wp.
3.2 extendObjectLifetimeIn RefBase, The extendObjectLifetime function is used to prolong the lifecycle of an object and is no longer affected by strong or weak references.
Void RefBase: extendObjectLifetime (int32_t mode) {android_atomic_or (mode, & mRefs-> mFlags); // or operation}
Two lifecycles are defined. mFlag defaults to 0, that is, Strong, which can be set to weak. After the settings are complete, the criteria for deleting the target object are different.
//! Flags for extendObjectLifetime()    enum {        OBJECT_LIFETIME_STRONG  = 0x0000,        OBJECT_LIFETIME_WEAK    = 0x0001,        OBJECT_LIFETIME_MASK    = 0x0001    };


Related Article

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.