C++ 智能指針
一、RefBase.h
class RefBase
{
public:
void incStrong(const void* id) const;
void decStrong(const void* id) const;
int getStrongCount() const;
class weakref_type
{
public:
RefBase* refBase() const;
void incWeak(const void* id);
void decWeak(const void* id);
bool attemptIncStrong(const void* id);
int getWeakCount() const;
};
weakref_type* createWeak(const void* id) const;
weakref_type* getWeakRefs() const;
protected:
RefBase();
virtual ~RefBase();//delete this時候會調用子類
enum {
OBJECT_LIFETIME_WEAK = 0x0001,
OBJECT_LIFETIME_FOREVER = 0x0003
};
void extendObjectLifetime(int mode);
enum {
FIRST_INC_STRONG = 0x0001
};
virtual bool onIncStrongAttempted(int flags,
const void* id);//子類可以覆蓋
private:
//friend class weakref_type;
class weakref_impl; //不能include,只能前向聲明
RefBase(const RefBase& o);
RefBase& operator=(const RefBase& o);
weakref_impl* const mRefs;
};
// ---------------------------------------------------------------------------
template <typename T>
class sp
{
public:
typedef typename RefBase::weakref_type weakref_type;
//相當於typedef RefBase::weakref_type weakref_typ
inline sp() : m_ptr(0) { }
sp(T* other);
sp(const sp<T>& other);
~sp();
inline T& operator* () const { return *m_ptr; }
inline T* operator-> () const { return m_ptr; }
inline T* get() const { return m_ptr; }
private:
template<typename Y> friend class
wp;//wp可以操作sp的私有變量,如構造函數
sp(T* p, weakref_type* refs);
T* m_ptr;
};
// ---------------------------------------------------------------------------
template <typename T>
class wp
{
public:
typedef RefBase::weakref_type weakref_type;
wp(T* other);
wp(const wp<T>& other);
~wp();
sp<T> promote() const;
inline weakref_type* get_refs() const
{
return m_refs;
}
private:
T* m_ptr;//strongPointer
weakref_type* m_refs;//weakref_impl
};
// ---------------------------------------------------------------------------
template<typename T>
sp<T>::sp(T* other)
: m_ptr(other)//strongPointer
{
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);
}
}
template<typename T>
sp<T>::~sp()
{
if (m_ptr) {
m_ptr->decStrong(this);
}
}
template<typename T>
sp<T>::sp(T* p, weakref_type* refs)
: m_ptr((p && refs->attemptIncStrong(this)) ? p : 0)
{
}
// ---------------------------------------------------------------------------
template<typename T>
wp<T>::wp(T* other)
: m_ptr(other)//strongPointer
{
if (other) {
m_refs = other->createWeak(this); //weakref_impl
}
}
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()
{
if (m_ptr) {
m_refs->decWeak(this);
}
}
template<typename T>
sp<T> wp<T>::promote() const
{
return sp<T>(m_ptr, m_refs);
}
二、RefBase.cpp
#include "RefBase.h"
#include <iostream>
using namespace std;
#define INITIAL_STRONG_VALUE (1<<28)
class RefBase::weakref_impl : public RefBase::weakref_type
{
public:
volatile int mStrong;
volatile int mWeak;
RefBase* const mBase;
volatile int mFlags;
weakref_impl(RefBase* base)
: mStrong(INITIAL_STRONG_VALUE)
, mWeak(0)
, mBase(base)
, mFlags(0)
{
}
~weakref_impl()
{
// cout << "~weakref_impl" << endl;
}
};
// ---------------------------------------------------------------------------
void RefBase::incStrong(const void* id) const
{
weakref_impl* const refs = mRefs;
refs->incWeak(id);
const int c = refs->mStrong++;
if (c != INITIAL_STRONG_VALUE) {
return;
}
refs->mStrong = refs->mStrong - INITIAL_STRONG_VALUE;
}
void RefBase::decStrong(const void* id) const
{
weakref_impl* const refs = mRefs;
const int c = --refs->mStrong;
if (c == 0) {
if ((refs->mFlags & OBJECT_LIFETIME_WEAK) !=
OBJECT_LIFETIME_WEAK) { //受到強指針控制
delete this;
}
}
refs->decWeak(id);
}
int RefBase::getStrongCount() const
{
return mRefs->mStrong;
}
RefBase* RefBase::weakref_type::refBase() const
{
return static_cast<const weakref_impl*>(this)->mBase;
}
void RefBase::weakref_type::incWeak(const void* id)
{
weakref_impl* const impl = static_cast<weakref_impl*>(this);
impl->mWeak++;
}
void RefBase::weakref_type::decWeak(const void* id)
{
weakref_impl* const impl = static_cast<weakref_impl*>(this);
const int c = --impl->mWeak;
if (c != 0) {
return;
}
if ((impl->mFlags & OBJECT_LIFETIME_WEAK) !=
OBJECT_LIFETIME_WEAK) { //受強指針控制
if (impl->mStrong == INITIAL_STRONG_VALUE) {
delete impl->mBase;
} else {
delete impl;
}
} else {
if ((impl->mFlags & OBJECT_LIFETIME_FOREVER) !=
OBJECT_LIFETIME_FOREVER) { //受弱指針控制
delete impl->mBase;
}
}
}
bool RefBase::weakref_type::attemptIncStrong(const void* id)
{
incWeak(id);//先增加,後面有減少,整體不變
weakref_impl* const impl = static_cast<weakref_impl*>(this);
int curCount = impl->mStrong;
if (curCount > 0 &&
curCount != INITIAL_STRONG_VALUE) {//mStrong變化過,且大於0
impl->mStrong = curCount + 1;
curCount = impl->mStrong;
}
if (curCount <= 0 ||
curCount ==
INITIAL_STRONG_VALUE) {//mStrong沒有變化過;或者變化後,為0
bool allow;
if (curCount == INITIAL_STRONG_VALUE) {
allow = (impl->mFlags & OBJECT_LIFETIME_WEAK) != OBJECT_LIFETIME_WEAK
|| impl->mBase->onIncStrongAttempted(FIRST_INC_STRONG, id);
} else {
allow = (impl->mFlags & OBJECT_LIFETIME_WEAK) == OBJECT_LIFETIME_WEAK
&& impl->mBase->onIncStrongAttempted(FIRST_INC_STRONG, id);
}
if (!allow) {
decWeak(id);//再減少
return false;
}
curCount = impl->mStrong++;
}
if (curCount == INITIAL_STRONG_VALUE) {
impl->mStrong = impl->mStrong - INITIAL_STRONG_VALUE;
}
return true;
}
int RefBase::weakref_type::getWeakCount() const
{
return static_cast<const weakref_impl*>(this)->mWeak;
}
RefBase::weakref_type* RefBase::createWeak(const void* id) const
{
mRefs->incWeak(id);
return mRefs;
}
RefBase::weakref_type* RefBase::getWeakRefs() const
{
return mRefs;
}
RefBase::RefBase()
: mRefs(new weakref_impl(this))
{
}
RefBase::~RefBase()
{
if (mRefs->mWeak == 0) {
delete mRefs;
}
}
void RefBase::extendObjectLifetime(int mode)
{
mRefs->mFlags = mode;
}
bool RefBase::onIncStrongAttempted(int flags, const void* id)
{
return (flags & FIRST_INC_STRONG) ? true : false;
}
void RefBase::decStrong(const void* id) const
{
weakref_impl* const refs = mRefs;
const int c = --refs->mStrong;
if (c == 0) {
if ((refs->mFlags & OBJECT_LIFETIME_WEAK) !=
OBJECT_LIFETIME_WEAK) { //受到強指針控制
delete this;
}
}
refs->decWeak(id);
}
減少強引用計數時候,同時減少弱引用計數,如果強引用計數為0,並且受強指針控制,那麼調用子類和RefBase的析構函數
void RefBase::weakref_type::decWeak(const void* id)
{
weakref_impl* const impl = static_cast<weakref_impl*>(this);
const int c = --impl->mWeak;
if (c != 0) {
return;
}
if ((impl->mFlags & OBJECT_LIFETIME_WEAK) !=
OBJECT_LIFETIME_WEAK) { //受強指針控制
if (impl->mStrong == INITIAL_STRONG_VALUE) {
delete impl->mBase;
} else {
delete impl;
}
} else {
if ((impl->mFlags & OBJECT_LIFETIME_FOREVER) !=
OBJECT_LIFETIME_FOREVER) { //受弱指針控制
delete impl->mBase;
}
}
}
RefBase::~RefBase()
{
if (mRefs->mWeak == 0) {
delete mRefs;
}
}
- 減少弱引用計數,如果弱引用計數為0,並且受弱指針控制,那麼調用delete impl->mBase,調用上面的析構函數,因為此時mWeek==0,所以執行delete mRefs
- 如果弱引用計數為0,並且不受強指針,也不受弱指針控制,那麼由自己調用delete來刪除
- 如果弱引用計數為0,並且受強指針控制,如果強引用計數為0,那麼只delete impl,因為RefBase及其子類已經被delelte掉了
- 如果弱引用計數為0,並且受強指針控制,如果強引用計數為INITIAL_STRONG_VALUE,那麼說明RefBase及其子類還沒有刪除,那麼要delelte impl->mBase,調用上面的析構函數,因為此時mWeek==0,所以執行delete mRefs
bool RefBase::weakref_type::attemptIncStrong(const void* id)
{
incWeak(id);
weakref_impl* const impl = static_cast<weakref_impl*>(this);
int curCount = impl->mStrong;
if (curCount > 0 && curCount != INITIAL_STRONG_VALUE) {
impl->mStrong = curCount + 1;
curCount = impl->mStrong;
}
if (curCount <= 0 || curCount == INITIAL_STRONG_VALUE) {
bool allow;
if (curCount == INITIAL_STRONG_VALUE) {
allow = (impl->mFlags & OBJECT_LIFETIME_WEAK) != OBJECT_LIFETIME_WEAK
|| impl->mBase->onIncStrongAttempted(FIRST_INC_STRONG, id);
} else {
allow = (impl->mFlags & OBJECT_LIFETIME_WEAK) == OBJECT_LIFETIME_WEAK
&& impl->mBase->onIncStrongAttempted(FIRST_INC_STRONG, id);
}
if (!allow) {
decWeak(id);
return false;
}
curCount = impl->mStrong++;
}
if (curCount == INITIAL_STRONG_VALUE + 1) {
impl->mStrong = impl->mStrong - INITIAL_STRONG_VALUE;
}
return true;
}
if (curCount > 0 && curCount != INITIAL_STRONG_VALUE)
{
impl->mStrong = curCount + 1;
curCount = impl->mStrong;
}
如果此時強引用計數不為0,或者初始值,那麼說明RefBase及其子類還沒有刪除,所以可以提升為強引用
allow = (impl->mFlags& OBJECT_LIFETIME_WEAK) == OBJECT_LIFETIME_WEAK
&& impl->mBase->onIncStrongAttempted(FIRST_INC_STRONG, id);
- 如果此時強引用計數為0,並且還受強指針控制,那麼此時,RefBase及其子類已經被刪除了,所以不能提升為強引用
- 如果此時強引用計數為0,並且還受弱指針控制,那麼此時,RefBase及其子類還沒有刪除,能不能提升就看impl->mBase->onIncStrongAttempted(FIRST_INC_STRONG, id)的了
allow = (impl->mFlags&OBJECT_LIFETIME_WEAK) != OBJECT_LIFETIME_WEAK
|| impl->mBase->onIncStrongAttempted(FIRST_INC_STRONG, id);
如果此時強引用計數為INITIAL_STRONG_VALUE,並且還受強指針控制,此時RefBase及其子類還沒有刪除,所以能夠提升。
如果此時強引用計數為INITIAL_STRONG_VALUE,並且還受弱指針控制,此時RefBase及其子類還沒有刪除,能不能提升就看impl->mBase->onIncStrongAttempted(FIRST_INC_STRONG, id)的了
- main.cpp
#include <stdio.h>
#include <iostream>
#include "RefBase.h"
using namespace std;
#define INITIAL_STRONG_VALUE (1<<28)
class WeightClass: public RefBase
{
public:
void printRefCount()
{
int strong = getStrongCount();
weakref_type* ref = getWeakRefs();
printf("-----------------------\n");
printf("Strong Ref Count: %d.\n",
(strong == INITIAL_STRONG_VALUE ? 0 : strong));
printf("Weak Ref Count: %d.\n", ref->getWeakCount());
printf("-----------------------\n");
}
};
class StrongClass: public WeightClass
{
public:
StrongClass()
{
printf("Construct StrongClass Object.\n");
}
virtual ~StrongClass()
{
printf("Destory StrongClass Object.\n");
}
};
class WeakClass: public WeightClass
{
public:
WeakClass()
{
extendObjectLifetime(OBJECT_LIFETIME_WEAK);
printf("Construct WeakClass Object.\n");
}
virtual ~WeakClass()
{
printf("Destory WeakClass Object.\n");
}
};
class ForeverClass: public WeightClass
{
public:
ForeverClass()
{
extendObjectLifetime(OBJECT_LIFETIME_FOREVER);
printf("Construct ForeverClass Object.\n");
}
virtual ~ForeverClass()
{
printf("Destory ForeverClass Object.\n");
}
};
void TestStrongClass(StrongClass* pStrongClass)
{
wp<StrongClass> wpOut = pStrongClass;
pStrongClass->printRefCount();
{
sp<StrongClass> spInner = pStrongClass;
pStrongClass->printRefCount();
}
pStrongClass->printRefCount();
sp<StrongClass> spOut = wpOut.promote();
printf("spOut: %p.\n", spOut.get());
pStrongClass->printRefCount();
}
void TestStrongClass2(StrongClass* pStrongClass)
{
wp<StrongClass> wpOut = pStrongClass;
pStrongClass->printRefCount();
}
void TestStrongClass4(StrongClass* pStrongClass)
{
wp<StrongClass> wpOut = pStrongClass;
pStrongClass->printRefCount();
sp<StrongClass> spInner = pStrongClass;
pStrongClass->printRefCount();
sp<StrongClass> spOut = wpOut.promote();
printf("spOut: %p.\n", spOut.get());
pStrongClass->printRefCount();
}
void TestStrongClass3(StrongClass* pStrongClass)
{
wp<StrongClass> wpOut = pStrongClass;
pStrongClass->printRefCount();
sp<StrongClass> spOut = wpOut.promote();
printf("spOut: %p.\n", spOut.get());
pStrongClass->printRefCount();
}
void TestWeakClass(WeakClass* pWeakClass)
{
wp<WeakClass> wpOut = pWeakClass;
pWeakClass->printRefCount();
{
sp<WeakClass> spInner = pWeakClass;
pWeakClass->printRefCount();
}
pWeakClass->printRefCount();
sp<WeakClass> spOut = wpOut.promote();
printf("spOut: %p.\n", spOut.get());
pWeakClass->printRefCount();
}
void TestForeverClass(ForeverClass* pForeverClass)
{
wp<ForeverClass> wpOut = pForeverClass;
pForeverClass->printRefCount();
{
sp<ForeverClass> spInner = pForeverClass;
pForeverClass->printRefCount();
}
pForeverClass->printRefCount();
}
int main(int argc, char** argv)
{
/* printf("Test Strong Class: \n");
StrongClass* pStrongClass = new StrongClass();
TestStrongClass(pStrongClass);*/
/* printf("Test Strong Class2: \n");
StrongClass* pStrongClass = new StrongClass();
TestStrongClass2(pStrongClass);*/
/* printf("\nTest Weak Class: \n");
WeakClass* pWeakClass = new WeakClass();
TestWeakClass(pWeakClass);*/
/* printf("\nTest Froever Class: \n");
ForeverClass* pForeverClass = new ForeverClass();
TestForeverClass(pForeverClass);
pForeverClass->printRefCount();
delete pForeverClass;*/
/* printf("Test Strong Class3: \n");
StrongClass* pStrongClass = new StrongClass();
TestStrongClass3(pStrongClass);*/
printf("Test Strong Class4: \n");
StrongClass* pStrongClass = new StrongClass();
TestStrongClass4(pStrongClass);
return 0;
}
g++ main.cpp RefBase.cpp -o main
Test Strong Class4:
Construct StrongClass Object.
-----------------------
Strong Ref Count: 0.
Weak Ref Count: 1.
-----------------------
-----------------------
Strong Ref Count: 1.
Weak Ref Count: 2.
-----------------------
spOut: 0x2308c20.
-----------------------
Strong Ref Count: 2.
Weak Ref Count: 3.
-----------------------
Destory StrongClass Object.
~weakref_impl