android中的智慧型指標

2021-06-26 05:52:59 字數 4908 閱讀 5809

本文參考了《深入理解android卷i>>第五章,感謝作者!

智慧型指標主要用來解決多個指標指向同一物件時,乙個指標被銷毀時刪除了物件導致的指標懸掛問題.  

智慧型指標的實現原理:使用引用計數來管理指向對像的拷貝,智慧型指標將乙個計數器和指向的對像關聯起來,在建立智慧型指標時將計數器初始化為1(使用指向的對像來建立),使用其他智慧型指標進行建立時將呼叫拷貝建構函式,拷貝建構函式將計數器加1,對其他智慧型指標賦值時減少左值的計數值增加右值的計數值,釋放指標將呼叫析構函式,析構函式中減少計數器的值.在任何情況下,減少計數器的值後,檢查計數值是否為0,如果為0就刪除指向對像.  

為了看得清楚些,忽略o和o2的指標懸掛問題..

object o=new object();

smartptr p1(o); // --->初始化o的計數值c(o)=1

smartptr p2(p1); //--->呼叫拷貝建構函式,c(o)加1 , c(o)==2

object o2=new object();

smartptr p3(o2);// c(o2)=1

p3=p1;// 減少c(o2),增加c(o), 則:c(o2)==0,刪除對像o2,c(o)==3

delete p1; // c(o)減1, c(o)==2

delete p2;// c(o)減1 ,c(o)==1

delete p3;// c(o)減1,c(o)==0,刪除對像o.

智慧型指標是c++中概念,android中有類似的東西,用來控制對像的生命週期,以便用於記憶體自動**.android使用refbase來管理計數值,sp,wp來管理智慧型指標,通過這樣的機制控制對像的生命週期.

1.refbase:

refbase有兩個內部類weakref_type和weakref_impl,refbase把weakref_type指定為友元,同時包含了乙個指向weakref_impl對像的指標mrefs.  

建立refbase對像時,其實建立了兩個對像,乙個是refbase自身,乙個是weakref_impl對像,weakref_impl對像就是用來管理refbase自身對像(可以稱為真實對像)的.

weakref_impl繼承weakref_type,包含了乙個指向refbase對像的指標mbase.  

weakref_impl中成員:

volatile int32_t    mstrong; //強引用計數

volatile int32_t mweak; //弱引用計數

refbase* const mbase; //用來指向真實對像

volatile int32_t mflags;//用來指定真實對像生命週期管理方式

包含了一組什麼也沒幹的函式:(注意這是release版本,除錯版本不是空的,因此這組函式其實是用於除錯用的,在分析時可以忽略)
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)

建構函式

refbase::refbase()

: mrefs(new weakref_impl(this)) //在初始化時建立了weakref_impl對像賦值給mrefs

weakref_impl(refbase* base)

: mstrong(initial_strong_value) //強引用計數初始化為initial_strong_value

, mweak(0)//弱引用計數初始化為0

, mbase(base)//指向真實對像,上面傳入的this指標

, mflags(0)//強引用計數管理生命週期

析構函式,當真實對像被析構時呼叫

refbase::~refbase()

else

}}  const_cast(mrefs) = null;

}

在析構函式中,檢查強引用計數是否為初始值,如果是就刪除weakref_impl對像,為什麼這樣的做呢?因為如果強引用計數為初始值,說明這次析構一定是由弱引用計數值為0引發的!如果強引用計數不為初始值,那麼說明析構可能是因為強引用計數減至0引發也可能由弱引用計數減至0引發,檢查對像生命週期管理方式是否為弱引用計數管理,如果是那麼再檢查弱引用計數,如果弱引用計數為0,則刪除weakref_impl對像.

增加弱引用計數.

void refbase::weakref_type::incweak(const void* id)

呼叫incweak僅增加弱引用計數.

減少弱引用計數

void refbase::weakref_type::decweak(const void* id)

else

} else

}}

呼叫decweak減少弱引用計數,如果弱引用計數減至0,那麼需要考慮刪除真實對像和weakref_impl對像了:   對像採用強引用計數管理生命週期:  1.1強引用計數還是初始值,沒有人使用,那麼需要刪除真實對像,刪除真實對像會引發析構函式,從而刪除weakref_impl對像.  1.2 強引用計數不是初始值,被使用過了,那麼只需要刪除weakref_impl對像.  對像採用弱引用計數管理生命週期:刪除真實對像,在引發的析構函式中刪除weakref_impl對像.因此decweak將弱引用計數減至0時,除了對像使用強引用計數管理生命週期並且強引用計數被使用過的情況外,都會刪除真實對像,在任何情況下都會刪除weakref_impl對像.

增加強引用計數

void refbase::incstrong(const void* id) const

android_atomic_add(-initial_strong_value, &refs->mstrong);//強引用計數-initial_strong_value,強引用計數現在等於1

refs->mbase->onfirstref();//refbase的繼承者可以覆蓋此函式,在第一次引用時來做一些初始化操作

}

呼叫incstrong,會同時增加強引用計數和弱引用計數

減少強引用計數:

void refbase::decstrong(const void* id) const

}refs->decweak(id);//弱引用減1

}

呼叫decstrong會同時減少強引用計數和弱引用計數,而且如果強引用計數減少到0並且對像採用強引用計數管理生命週期的話需要刪除真實對像.

設定對像的生命週期:

enum ;

void refbase::extendobjectlifetime(int32_t mode)

總結:對像生命週期管理方式為強引用計數管理時,當強引用計數減至0,對像一定會被刪除,但是它的weakref_impl對像不一定被刪除,當弱引用計數減至0時weakref_impl對像一定會被刪除,但是對像不一定被刪除.對像生命週期為弱引用計數管理時,當強引用計數減至0,對像和weakref_impl對像都不會被刪除,當弱引用計數減至0時,對像會被刪除,然後weakref_impl對像會在析構函式中被刪除.

嘗試增加強引用計數

bool refbase::weakref_type::attemptincstrong(const void* id)

curcount = impl->mstrong;

}if (curcount <= 0 || curcount == initial_strong_value) else

if (!allow)

curcount = android_atomic_inc(&impl->mstrong);//增加強引用計數,返回舊值

if (curcount > 0 && curcount < initial_strong_value)

}impl->addstrongref(id);

if (curcount == initial_strong_value)

return true;

}

嘗試增加弱引用計數:

bool refbase::weakref_type::attemptincweak(const void* id)

curcount = impl->mweak;

}if (curcount > 0)

return curcount > 0;//當前弱引用計數為0時代表weakref_impl對像已釋放,所以增加弱引用計數會失敗

}

2.sp,wp

refbase用來管理對像的計數值,而sp用來建立對像的強指標,wp用來建立弱指標.建立sp時會呼叫incstrong,析構sp時會呼叫decstrong,建立wp時會呼叫createweak或incweak,析構wp時會呼叫decweak.sp和wp都會過載操作符=,依據智慧型指標的原理管理計數值.  

sp和wp的互相轉換:sp->wp直接通過wp的建構函式,wp->sp通過wp的promote函式.

android智慧型指標的原理

看android的c 的 到處都是智慧型指標 一直看不懂類似的 spmakecrypto sm是個sp物件,它怎麼有成員函式getservice?仔細研究sp的 template class sp inline t operator const inline t get const private ...

智慧型指標類模板(中) Qt中的智慧型指標

qt中的智慧型指標 qpointer 當其指向的物件被銷毀時,它會被自動置空 析構時不會自動銷毀所指向的物件 qsharedpointer 引用計數型智慧型指標 可以被自由的拷貝和賦值 當引用計數為0時才刪除指向的物件 include include using namespace std clas...

智慧型指標類模板(中) Qt中的智慧型指標

qt中的智慧型指標 qpointer 當其指向的物件被銷毀時,它會被自動置空 析構時不會自動銷毀所指向的物件 qsharedpointer 引用計數型智慧型指標 可以被自由的拷貝和賦值 當引用計數為0時才刪除指向的物件 include include using namespace std clas...