智能指针的目标
在使用指针的时候容易出现的问题不外乎下面几个。首先,指针在使用之前都必须初始化,这个还算容易解决,在创建指针变量的时候同步初始化就好了;第二个问题就是经常忘记delete,就我的经验来看,这个还是很容易忘记的,在一个大型程序中要是有那么几个地方忘记执行delete,长久来看系统内存肯定会被消耗完;第三个问题就是就算记得delete,但是也不是说delete就delete的,要是还有别的对象在引用这个对象,然后被delete了,那么在其他地方访问这个对象的时候程序肯定会奔溃的。
有了智能指针后,上面的问题就好办了,首先创建智能指针的时候也同时创建需要管理的对象,然后将需要管理的对象委托给智能指针来管理就好了。在智能指针内部管理着一个引用计数值,当有新的智能指针引用这个对象时,引用计数值加一,当本来引用该对象的智能指针指向其他对象时,那么引用计数值就减一,当引用计数值减为0的时候就智能指针会帮忙将对象delete,也就解决了忘记delete以及在错误时刻进行delete的困境了。这样上面出现的问题就都能很好的解决了。
轻量级指针
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 |
template <class T> class LightRefBase { public: inline LightRefBase() : mCount(0) { } inline void incStrong(__attribute__((unused)) const void* id) const { android_atomic_inc(&mCount); } inline void decStrong(__attribute__((unused)) const void* id) const { if (android_atomic_dec(&mCount) == 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 ~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 volatile int32_t mCount; }; |
首先看一下轻量级指针,轻量级指针属于模板类,要想使用轻量级指针的功能只要在创建自身类的时候继承这个类就OK了,然后在这个类内部组织管理着一个引用计数值。这个值的功能和前面说的一样,起到控制对象生命周期的作用。incStrong和decStrong起到减少和增加引用计数值的功能。
因为LightRefBase内没有用来保存待委托对象的指针,所以LightRefBase不算是智能指针,大概算是指针的升级版本。以这个类作为基类的类还需要搭配真正的智能指针才能发挥作用。之后会介绍真正的智能指针sp和wp。
强指针
sp类
sp类相对简单,大家看一下代码的实现基本也能了解,下面会配合Refbase进行简单的分析。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 |
template<typename T> class sp { public: inline sp() : m_ptr(0) { } sp(T* other); sp(const sp<T>& other); template<typename U> sp(U* other); template<typename U> sp(const sp<U>& other); ~sp(); // Assignment sp& operator = (T* other); sp& operator = (const sp<T>& other); template<typename U> sp& operator = (const 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; }; |
强指针使用的引用计数类是RefBase,它比LightRefBase复杂得多,所以后者才会被称为轻量级指针。下面看一下RefBase的代码:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 |
class RefBase { public: void incStrong(const void* id) const; void decStrong(const void* id) const; void forceIncStrong(const void* id) const; //! DEBUGGING ONLY: Get current strong ref count. int32_t getStrongCount() const; class weakref_type { public: RefBase* refBase() const; void incWeak(const void* id); void decWeak(const void* id); // acquires a strong reference if there is already one. bool attemptIncStrong(const void* id); // acquires a weak reference if there is already one. // This is not always safe. see ProcessState.cpp and BpBinder.cpp // for proper use. bool attemptIncWeak(const void* id); //! DEBUGGING ONLY: Get current weak ref count. int32_t getWeakCount() const; //! DEBUGGING ONLY: Print references held on object. void printRefs() const; //! DEBUGGING ONLY: Enable tracking for this object. // enable -- enable/disable tracking // retain -- when tracking is enable, if true, then we save a stack trace // for each reference and dereference; when retain == false, we // match up references and dereferences and keep only the // outstanding ones. void trackMe(bool enable, bool retain); }; weakref_type* createWeak(const void* id) const; weakref_type* getWeakRefs() const; //! DEBUGGING ONLY: Print references held on object. inline void printRefs() const { getWeakRefs()->printRefs(); } //! DEBUGGING ONLY: Enable tracking of object. inline void trackMe(bool enable, bool retain) { getWeakRefs()->trackMe(enable, retain); } typedef RefBase basetype; protected: RefBase(); virtual ~RefBase(); //! Flags for extendObjectLifetime() enum { OBJECT_LIFETIME_STRONG = 0x0000, OBJECT_LIFETIME_WEAK = 0x0001, OBJECT_LIFETIME_MASK = 0x0001 }; void extendObjectLifetime(int32_t mode); //! Flags for onIncStrongAttempted() enum { FIRST_INC_STRONG = 0x0001 }; virtual void onFirstRef(); virtual void onLastStrongRef(const void* id); virtual bool onIncStrongAttempted(uint32_t flags, const void* id); virtual void onLastWeakRef(const void* id); private: friend class weakref_type; class weakref_impl; RefBase(const RefBase& o); RefBase& operator=(const RefBase& o); private: friend class ReferenceMover; static void renameRefs(size_t n, const ReferenceRenamer& renamer); static void renameRefId(weakref_type* ref, const void* old_id, const void* new_id); static void renameRefId(RefBase* ref, const void* old_id, const void* new_id); weakref_impl* const mRefs; }; |
RefBase和LightRefBase一样提供了incStrong和decStrong成员函数来操作引用计数器;而RefBase和LightRefbase类最大的区别就是它不像LightRefBase那么简单,只提供一个引用计数器,而是提供了一个强引用计数器和一个弱引用计数器。这两种计数器的功能是由weakref_impl类的变量mRefs提供的。
weakref_impl类
RefBase类的成员变量mRefs的类型为weakref_impl指针,这个类的代码在RefBase.cpp文件内,里面的代码看似很复杂,其实细心了解下里面有一个DEBUG_REFS宏,这个宏里面的代码只有在Debug版本下才会去实现,否则为空,所以基本可以不用看。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 |
class RefBase::weakref_impl : public RefBase::weakref_type { public: volatile int32_t mStrong; volatile int32_t mWeak; RefBase* const mBase; volatile int32_t mFlags; #if !DEBUG_REFS weakref_impl(RefBase* base) : mStrong(INITIAL_STRONG_VALUE) , mWeak(0) , mBase(base) , mFlags(0) { } void addStrongRef(const void* /*id*/) { } void removeStrongRef(const void* /*id*/) { } void renameStrongRefId(const void* /*old_id*/, const void* /*new_id*/) { } void addWeakRef(const void* /*id*/) { } void removeWeakRef(const void* /*id*/) { } void renameWeakRefId(const void* /*old_id*/, const void* /*new_id*/) { } void printRefs() const { } void trackMe(bool, bool) { } #else weakref_impl(RefBase* base) : mStrong(INITIAL_STRONG_VALUE) , mWeak(0) , mBase(base) , mFlags(0) , mStrongRefs(NULL) , mWeakRefs(NULL) , mTrackEnabled(!!DEBUG_REFS_ENABLED_BY_DEFAULT) , mRetain(false) { } ~weakref_impl() { bool dumpStack = false; if (!mRetain && mStrongRefs != NULL) { dumpStack = true; ALOGE("Strong references remain:"); ref_entry* refs = mStrongRefs; while (refs) { char inc = refs->ref >= 0 ? '+' : '-'; ALOGD("\t%c ID %p (ref %d):", inc, refs->id, refs->ref); #if DEBUG_REFS_CALLSTACK_ENABLED refs->stack.log(LOG_TAG); #endif refs = refs->next; } } if (!mRetain && mWeakRefs != NULL) { dumpStack = true; ALOGE("Weak references remain!"); ref_entry* refs = mWeakRefs; while (refs) { char inc = refs->ref >= 0 ? '+' : '-'; ALOGD("\t%c ID %p (ref %d):", inc, refs->id, refs->ref); #if DEBUG_REFS_CALLSTACK_ENABLED refs->stack.log(LOG_TAG); #endif refs = refs->next; } } if (dumpStack) { ALOGE("above errors at:"); CallStack stack(LOG_TAG); } } void addStrongRef(const void* id) { //ALOGD_IF(mTrackEnabled, // "addStrongRef: RefBase=%p, id=%p", mBase, id); addRef(&mStrongRefs, id, mStrong); } void removeStrongRef(const void* id) { //ALOGD_IF(mTrackEnabled, // "removeStrongRef: RefBase=%p, id=%p", mBase, id); if (!mRetain) { removeRef(&mStrongRefs, id); } else { addRef(&mStrongRefs, id, -mStrong); } } ……….. void addWeakRef(const void* id) { addRef(&mWeakRefs, id, mWeak); } void removeWeakRef(const void* id) { if (!mRetain) { removeRef(&mWeakRefs, id); } else { addRef(&mWeakRefs, id, -mWeak); } } …………… private: struct ref_entry { ref_entry* next; const void* id; #if DEBUG_REFS_CALLSTACK_ENABLED CallStack stack; #endif int32_t ref; }; void addRef(ref_entry** refs, const void* id, int32_t mRef) { if (mTrackEnabled) { AutoMutex _l(mMutex); ref_entry* ref = new ref_entry; // Reference count at the time of the snapshot, but before the // update. Positive value means we increment, negative--we // decrement the reference count. ref->ref = mRef; ref->id = id; #if DEBUG_REFS_CALLSTACK_ENABLED ref->stack.update(2); #endif ref->next = *refs; *refs = ref; } } void removeRef(ref_entry** refs, const void* id) { if (mTrackEnabled) { AutoMutex _l(mMutex); ref_entry* const head = *refs; ref_entry* ref = head; while (ref != NULL) { if (ref->id == id) { *refs = ref->next; delete ref; return; } refs = &ref->next; ref = *refs; } ALOGE("RefBase: removing id %p on RefBase %p" "(weakref_type %p) that doesn't exist!", id, mBase, this); ref = head; while (ref) { char inc = ref->ref >= 0 ? '+' : '-'; ALOGD("\t%c ID %p (ref %d):", inc, ref->id, ref->ref); ref = ref->next; } CallStack stack(LOG_TAG); } } …..….. mutable Mutex mMutex; ref_entry* mStrongRefs; ref_entry* mWeakRefs; bool mTrackEnabled; // Collect stack traces on addref and removeref, instead of deleting the stack references // on removeref that match the address ones. bool mRetain; #endif }; |
Weakref_impl类是weakref_base的子类,这个是接口与实现分离的思想。
RefBase的incStrong函数
1 2 3 4 5 6 7 8 9 10 11 12 13 |
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); } |
这里的other就是实际的对象,这个对象可以是继承了LightRefBase的对象也可以是继承了RefBase的对象,因为这里主要分析RefBase对象,所以这里以及下面的内容都假设other对象是继承了RefBase的内容的,下面看RefBase的incStrong函数
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 |
void RefBase::incStrong(const void* id) const { weakref_impl* const refs = mRefs; refs->incWeak(id); refs->addStrongRef(id); const int32_t c = android_atomic_inc(&refs->mStrong); ALOG_ASSERT(c > 0, "incStrong() called on %p after last strong ref", refs); #if PRINT_REFS ALOGD("incStrong of %p from %p: cnt=%d\n", this, id, c); #endif if (c != INITIAL_STRONG_VALUE) { return; } android_atomic_add(-INITIAL_STRONG_VALUE, &refs->mStrong); refs->mBase->onFirstRef(); } |
其中mRefs实在RefBase的构造函数中创建的
1 2 3 4 |
RefBase::RefBase() : mRefs(new weakref_impl(this)) { } |
重新回到incStrong函数中,我们会发现这个函数中其实只是做了三件事情:
- 增加弱引用计数
refs->incWeak(id);
- 增加强引用计数
const int32_t c = android_atomic_inc(&refs->mStrong);
- 如果发现是第一次调用对象的incStrong,那么就会修正mStrong引用计数,然后调用这个对象的onFirstRef函数
1 2 |
android_atomic_add(-INITIAL_STRONG_VALUE, &refs->mStrong); refs->mBase->onFirstRef() |
在调用weakref_impl的构造函数的时候会将mStrong的值初始化为INITIAL_STRONG_VALUE=1<<28;那么在执行加1操作后,mStrong就等于1<<28+1;返回的值c等于加1前的值,即1<<28;所以第一次调用incStrong后需要对mStrong的值进行修正,加上-INITIAL_STRONG_VALUE正好。
现在回头看增加弱引用计数的代码,通过调用weakref_impl的incWeak来对弱引用计数进行加1操作,而weakref_impl类的incWeak则是直接从父类weakref_base中继承来的。
1 2 3 4 5 6 7 |
void RefBase::weakref_type::incWeak(const void* id) { weakref_impl* const impl = static_cast<weakref_impl*>(this); impl->addWeakRef(id); const int32_t c __unused = android_atomic_inc(&impl->mWeak); ALOG_ASSERT(c >= 0, "incWeak called on %p after last weak ref", this); } |
上面代码增加弱引用计数主要是执行android_atomic_inc方法来完成的。
RefBase的decStrong函数
1 2 3 4 5 |
template<typename T> sp<T>::~sp() { if (m_ptr) m_ptr->decStrong(this); } |
上面的代码调用RefBase类的decStrong函数
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 |
void RefBase::decStrong(const void* id) const { weakref_impl* const refs = mRefs; refs->removeStrongRef(id); const int32_t c = android_atomic_dec(&refs->mStrong); #if PRINT_REFS ALOGD("decStrong of %p from %p: cnt=%d\n", this, id, c); #endif ALOG_ASSERT(c >= 1, "decStrong() called on %p too many times", refs); if (c == 1) { refs->mBase->onLastStrongRef(id); if ((refs->mFlags&OBJECT_LIFETIME_MASK) == OBJECT_LIFETIME_STRONG) { delete this; } } refs->decWeak(id); } |
上面代码先将强引用计数减1,如果发现返回值为1的话,就代表调用此时强引用计数值已经为0了,那么就调用onLastStrongRef函数,这个函数在RefBase中的实现也是为空的,一般是留给子类来实现。然后判断mask是否为OBJECT_LISTTIME_STRONG,如果是,代表该对象的生命周期受强引用计数值控制,当这个对象的强引用计数值为0时,就将这个对象delete掉。
对弱引用计数值的操作则是调用decWeak.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 |
void RefBase::weakref_type::decWeak(const void* id) { weakref_impl* const impl = static_cast<weakref_impl*>(this); impl->removeWeakRef(id); const int32_t c = android_atomic_dec(&impl->mWeak); ALOG_ASSERT(c >= 1, "decWeak called on %p too many times", this); if (c != 1) return; // 如果对象受强引用控制 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. // 删除impl该对象 delete impl->mBase; } else { // ALOGV("Freeing refs %p of old RefBase %p\n", this, impl->mBase); // 这种时对象被强引用过了,所以只需要直接删除impl即可 delete impl; } } else { // less common case: lifetime is OBJECT_LIFETIME_{WEAK|FOREVER} impl->mBase->onLastWeakRef(id); if ((impl->mFlags&OBJECT_LIFETIME_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; } } } |
在这个函数中,当弱引用计数不为1则直接return,如果为1那么减1后就为0了,需要对对象进行delete操作。而弱引用计数为1又分为两种情况:
第一种情况为对象的生命周期只受强引用控制,而当强引用计数为初始值的时候,就要删除impl->mBase就是删除实际的对象。而RefBase被删除的时候就会调用析构函数,而在析构函数中决定是否需要将mRefs删除。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 |
RefBase::~RefBase() { if (mRefs->mStrong == INITIAL_STRONG_VALUE) { // 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) { // 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) { delete mRefs; } } } // for debugging purposes, clear this. const_cast<weakref_impl*&>(mRefs) = NULL; } |
当时如果强引用指数不为初始值的时候,就直接调用delete impl,那是因为在decStrong函数中就已经将实际的对象delete掉了。
第二种情况,当对象的生命周期不受强引用控制时,先调用onLastWeakRef函数,然后如果对象的生命周期时由弱引用控制,就直接删除RefBase对象,当然在RefBase的析构函数中也会删除mRefs对象。
弱指针
wp类
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 |
template <typename T> class wp { public: typedef typename RefBase::weakref_type weakref_type; 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); ~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; T* m_ptr; weakref_type* m_refs; }; |
与强指针类相比,他们都有一个成员变量m_ptr指向目标对象,但是弱指针还有一个额外的成员变量m_refs,他的类型时weakref_type指针,下面我们分析弱指针的构造函数时再看看他是如何初始化的。这里我们需要关注的是构造函数和析构函数。
wp类的构造函数
先看看wp类的构造函数
1 2 3 4 5 6 |
template<typename T> wp<T>::wp(T* other) : m_ptr(other) { if (other) m_refs = other->createWeak(this); } |
这里调用RefBase的createWeak函数,返回值为m_refs。
在RefBase的createWeak函数中,直接调用weakref_impl的incWeak函数,这个函数之前分析过了就是增加弱引用计数的,同时返回mRefs给调用函数。
1 2 3 4 5 |
RefBase::weakref_type* RefBase::createWeak(const void* id) const { mRefs->incWeak(id); return mRefs; } |
接下分析析构函数,这里直接调用weakref_impl的decWeak函数,前面分析过这个函数了。在这个函数里面弱引用次数减1,然后决定是否需要delete impl等。
1 2 3 4 5 |
template<typename T> wp<T>::~wp() { if (m_ptr) m_refs->decWeak(this); } |
升级为强指针
分析到这里,弱指针还没有分析完成,这里面还有一个非常重要的特性还没有分析,那就是将弱指针升级为强指针的操作,是直接调用其中的promote函数
1 2 3 4 5 6 7 8 9 |
template<typename T> sp<T> wp<T>::promote() const { sp<T> result; if (m_ptr && m_refs->attemptIncStrong(&result)) { result.set_pointer(m_ptr); } return result; } |