智能指针的目标
在使用指针的时候容易出现的问题不外乎下面几个。首先,指针在使用之前都必须初始化,这个还算容易解决,在创建指针变量的时候同步初始化就好了;第二个问题就是经常忘记delete,就我的经验来看,这个还是很容易忘记的,在一个大型程序中要是有那么几个地方忘记执行delete,长久来看系统内存肯定会被消耗完;第三个问题就是就算记得delete,但是也不是说delete就delete的,要是还有别的对象在引用这个对象,然后被delete了,那么在其他地方访问这个对象的时候程序肯定会奔溃的。
有了智能指针后,上面的问题就好办了,首先创建智能指针的时候也同时创建需要管理的对象,然后将需要管理的对象委托给智能指针来管理就好了。在智能指针内部管理着一个引用计数值,当有新的智能指针引用这个对象时,引用计数值加一,当本来引用该对象的智能指针指向其他对象时,那么引用计数值就减一,当引用计数值减为0的时候就智能指针会帮忙将对象delete,也就解决了忘记delete以及在错误时刻进行delete的困境了。这样上面出现的问题就都能很好的解决了。
轻量级指针
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进行简单的分析。
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的代码:
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版本下才会去实现,否则为空,所以基本可以不用看。
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函数
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函数
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的构造函数中创建的
RefBase::RefBase()
: mRefs(new weakref_impl(this))
{
}
重新回到incStrong函数中,我们会发现这个函数中其实只是做了三件事情:
- 增加弱引用计数
refs->incWeak(id); - 增加强引用计数
const int32_t c = android_atomic_inc(&refs->mStrong); - 如果发现是第一次调用对象的incStrong,那么就会修正mStrong引用计数,然后调用这个对象的onFirstRef函数
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中继承来的。
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函数
template<typename T>
sp<T>::~sp() {
if (m_ptr)
m_ptr->decStrong(this);
}
上面的代码调用RefBase类的decStrong函数
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.
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删除。
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(mRefs) = NULL;
}
当时如果强引用指数不为初始值的时候,就直接调用delete impl,那是因为在decStrong函数中就已经将实际的对象delete掉了。
第二种情况,当对象的生命周期不受强引用控制时,先调用onLastWeakRef函数,然后如果对象的生命周期时由弱引用控制,就直接删除RefBase对象,当然在RefBase的析构函数中也会删除mRefs对象。
弱指针
wp类
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类的构造函数
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给调用函数。
RefBase::weakref_type* RefBase::createWeak(const void* id) const
{
mRefs->incWeak(id);
return mRefs;
}
接下分析析构函数,这里直接调用weakref_impl的decWeak函数,前面分析过这个函数了。在这个函数里面弱引用次数减1,然后决定是否需要delete impl等。
template<typename T>
wp<T>::~wp()
{
if (m_ptr) m_refs->decWeak(this);
}
升级为强指针
分析到这里,弱指针还没有分析完成,这里面还有一个非常重要的特性还没有分析,那就是将弱指针升级为强指针的操作,是直接调用其中的promote函数
template<typename T>
sp<T> wp<T>::promote() const
{
sp result;
if (m_ptr && m_refs->attemptIncStrong(&result)) {
result.set_pointer(m_ptr);
}
return result;
}
智能指针详解
本文深入解析智能指针的概念与实现,包括轻量级指针LightRefBase、强指针sp和弱指针wp的工作原理及应用场景,帮助读者理解智能指针如何解决传统指针带来的问题。
884

被折叠的 条评论
为什么被折叠?



