引入智能指针的目的:
- 对象的引用计数应该有谁来维护?
- 如何解决对象循环引用的问题?
实现智能指针需要两步:一是为指向的对象关联引用计数,二是构造智能指针对象。
智能指针本身是一个对象,负责维护引用计数并根据引用计数delete引用对象。
{
...
};
{
...
};
classCDerivation : public CBase
{
...
};
using namespace std;
#include "RefCountedPointer.h"
#include "ReferenceCounter.h"
struct IInterfaceA
{
static int IA;
virtual void displayA(void)= 0;
virtual void displayB(void)= 0;
};
int IInterfaceA::IA = 100;
struct IInterfaceB
{
static int IB;
virtual void displayC(void)= 0;
virtual void displayD(void)= 0;
};
int IInterfaceB::IB = 102;
class CClass : publicReferenceCounter, public IInterfaceA, public IInterfaceB
{
public:
int a;
int b;
int c;
int d;
public:
virtual void displayA(void)
{
cout<<a;
}
virtual void displayB(void)
{
cout<<b;
}
virtual void displayC(void)
{
cout<<c;
}
virtual void displayD(void)
{
cout<<d;
}
};
void main(void)
{
RefCountedPointer<CClass> p = new CClass;
p->a = 0;
p->b = 1;
p->c = 2;
p->d = 3;
p->displayA();
cout<<endl;
p->displayB();
cout<<endl;
p->displayC();
cout<<endl;
p->displayD();
cout<<endl;
}
class LightRefBase
{
public:
inline LightRefBase() : mCount(0) { }
inline void incStrong(const void* id) const {
android_atomic_inc(&mCount);
}
inline void decStrong(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 moveReferences(void* d, void const* s, size_t n,
const ReferenceConverterBase& caster) { }
private:
mutable volatile int32_t mCount;
};
针对这个问题,可以采用对象的引用计数同时存在强引用和弱引用两种计数。例如A引用B则B的强引用计数和弱引用计数+1,而B引用A则A仅仅弱引用数+1,在回收时只要对象的强引用计数为0,则不管弱引用数是否为0都进行回收,类似于死锁解决中的强制释放资源,这样问题得到解决。
以下有几个概念容易混淆,先提出来辨析
强指针支持指向两种超类型的引用对象,一种是轻量级引用对象,继承自LightRefBase,另一种姑且称之为重量级引用对象,继承自RefBase。
弱指针只支持指向重量级引用对象,继承自RefBase。
引用对象负责维护自己的引用计数,但引用计数器增加或减少的消息由sp或是wp智能指针对象发生。
LightRefBase和RefBase维护引用计数的方式不相同,前者直接使用int型变量维护,或者使用一个嵌套类weakref_type维护。
强引用计数和弱引用计数:目标对象关联的两个计数属性,这两个计数属性同时存在,值由指针控制,不一定相等。
强指针和弱指针:是两个不同的智能指针对象,在创建对象、拷贝构造以及析构的时候改变引用对象的强引用计数和弱引用计数,两种指针的改变规则不同。
对象采用的引用计数方法:用flag表示目标对象在回收时受哪种强引用计数还是弱引用计数影响,4.0版本没有了forever模式。
弱指针无法直接访问对象,需要promote成强指针,但并不一定保证成功。
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;
};
class sp
{
public:
inline sp() : m_ptr(0) { }
sp(T* other);
sp(const sp<T>& other);
~sp();
private:
template<typename Y> friend class sp;
template<typename Y> friend class wp;
void set_pointer(T* ptr);
T* m_ptr;
};
sp(
const
sp<T>& other)
的实现如下:
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);
}
sp<T>::~sp()
{
if (m_ptr) m_ptr->decStrong(this);
}
{
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 ReferenceMover;
static void moveReferences(void* d, void const* s, size_t n,
const ReferenceConverterBase& caster);
private:
friend class weakref_type;
class weakref_impl;
RefBase(const RefBase& o);
RefBase& operator=(const RefBase& o);
weakref_impl* const mRefs;
};
{
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
......
#endif
};
: mRefs(new weakref_impl(this))
{
}
的incStrong。
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);
}
{
weakref_impl* const refs = mRefs;
refs->incWeak(id);
refs->addStrongRef(id);
const int32_t c = android_atomic_inc(&refs->mStrong);
LOG_ASSERT(c > 0, "incStrong() called on %p after last strong ref", refs);
#if PRINT_REFS
LOGD("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();
}
{
weakref_impl* const impl = static_cast<weakref_impl*>(this);
impl->addWeakRef(id);
const int32_t c = android_atomic_inc(&impl->mWeak);
LOG_ASSERT(c >= 0, "incWeak called on %p after last weak ref", this);
}
sp<T>::~sp()
{
if (m_ptr) m_ptr->decStrong(this);
}
{
weakref_impl* const refs = mRefs;
refs->removeStrongRef(id);
const int32_t c = android_atomic_dec(&refs->mStrong);
#if PRINT_REFS
LOGD("decStrong of %p from %p: cnt=%d\n", this, id, c);
#endif
LOG_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);
}
{
weakref_impl* const impl = static_cast<weakref_impl*>(this);
impl->removeWeakRef(id);
const int32_t c = android_atomic_dec(&impl->mWeak);
LOG_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.
delete impl->mBase;
} else {
// LOGV("Freeing refs %p of old RefBase %p\n", this, impl->mBase);
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;
}
}
}
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;
};
wp<T>::wp(T* other)
: m_ptr(other)
{
if (other) m_refs = other->createWeak(this);
}
template<typename T>
wp<T>::wp(const wp<T>& other)
: m_ptr(other.m_ptr), m_refs(other.m_refs)
{
if (m_ptr) m_refs->incWeak(this);
}
template<typename T>
wp<T>::wp(const sp<T>& other)
: m_ptr(other.m_ptr)
{
if (m_ptr) {
m_refs = m_ptr->createWeak(this);
}
}
{
mRefs->incWeak(id);
return mRefs;
}
{
weakref_impl* const impl = static_cast<weakref_impl*>(this);
impl->addWeakRef(id);
const int32_t c = android_atomic_inc(&impl->mWeak);
LOG_ASSERT(c >= 0, "incWeak called on %p after last weak ref", this);
}
wp<T>::~wp()
{
if (m_ptr) m_refs->decWeak(this);
}
sp<T> wp<T>::promote() const
{
sp<T> result;
if (m_ptr && m_refs->attemptIncStrong(&result)) {
result.set_pointer(m_ptr);
}
return result;
}
{
incWeak(id);
weakref_impl* const impl = static_cast<weakref_impl*>(this);
int32_t curCount = impl->mStrong;
LOG_ASSERT(curCount >= 0, "attemptIncStrong called on %p after underflow",
this);
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;
if (curCount == INITIAL_STRONG_VALUE) {
// Attempting to acquire first strong reference... this is allowed
// if the object does NOT have a longer lifetime (meaning the
// implementation 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) {
decWeak(id);
return false;
}
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 onLastStrongRef() 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->onLastStrongRef(id);
}
}
impl->addStrongRef(id);
#if PRINT_REFS
LOGD("attemptIncStrong of %p from %p: cnt=%d\n", this, id, curCount);
#endif
if (curCount == INITIAL_STRONG_VALUE) {
android_atomic_add(-INITIAL_STRONG_VALUE, &impl->mStrong);
impl->mBase->onFirstRef();
}
return true;
}