在C++中,我們常用指針去使用某個對象實例,但隨著代碼對該對象使用的增加,比如越來越多的其它的類或模塊需要使用該對象,那么什么時候安全地釋放該對象就是個問題。比如,某處使用完該對象后,認為不再使用,便釋放了它,但另外的某些類或模塊還需使用,這時,就會引起內存的非法使用問題,在Linux下是signal 11錯誤,也就是段錯誤(Segmentation Fault)。為了解決這種問題,引入了智能指針,當使用該對象時,令其引用計數(shù)加1,釋放時只是減去1。當減為0時,就自動釋放指針所指對象。C++中,通常使用模板實現(xiàn)這一機制。但是當兩個智能指針相互引用對方時,即使其它地方都釋放它們,它們的引用計數(shù)也會為1,最終導致內存泄漏。這就引入了弱指針的概念。 Android中的隨處可見的sp<XXX>和wp<XXX>。這里的XXX是對象的類,sp和wp是模版,分別實現(xiàn)了強指針(Strong Pointer)和弱指針(Weak Pointer)。模板具體化后的一個實例XXX,具有指針的屬性,可以簡單地把它理解一個指針,只不過比普通的指針特殊一點而已。弱指針不能直接被當作指針來使用,當需要當作指針來使用時,需要使用其成員函數(shù)promote來“提升”為強指針。弱指針指向的對象可能已經被銷毀,這時,若使用promote得到的指針為空指針。
引用計數(shù)功能的實現(xiàn) RefBase是引用計數(shù)的基類(見文件RefBase.h),在它里面還定義了一個嵌套類weakref_type,在其實現(xiàn)文件RefBase.cpp里還定義了一個類weakref_impl ,它繼承自嵌套類weakref_type,而RefBase中包含一個私有數(shù)據(jù)成員:指向weakref_impl 的指針??梢钥闯?,RefBase中的數(shù)據(jù)實體就是weakref_impl,后者繼承自其嵌套類weakref_type。其示意圖如下:
這樣,相當于將一部分成員函數(shù)(weakref_type的成員函數(shù))和數(shù)據(jù)成員(weakref_impl的數(shù)據(jù)成員)封裝起來,作為私有的一個邏輯實體,只被Refbase內部的實現(xiàn)使用,而RefBase的公有成員才是外界使用的API。RefBase通過指針mRefs使用內部的引用計數(shù)數(shù)據(jù)。而內部引用計數(shù)實體對象也可以通過 mBase這個成員來使用其“容器”對象RefBase. weakref_impl里面的數(shù)據(jù)成員信息如下: volatile int32_t mStrong;//強引用計數(shù)
強指針和弱指針都是模板類: template <typename T> class sp{ //……此處省略了部分代碼 inline T& operator* () const { return *m_ptr; } //……此處省略了部分代碼 T* m_ptr;//實際指向對象的指針 }; template <typename T> class wp{ //……此處省略了部分代碼 sp<T>promote() const; //……此處省略了部分代碼 T* m_ptr; }; 強指針因為重載了兩個操作符*和->,因此具有形式上跟普通指針一樣的用法,而弱指則沒有重載這兩個操作符,只能先被“提升”為強指針后,才可以當作普通指針來使用。 如果需要使用智能指針將對象保護起來,只要讓其繼承RefBase,并將析構函數(shù)聲明為virtual的,就可以使用智能指針。
可以參考鏈接來獲取詳細介紹:
參考: Android系統(tǒng)的智能指針(輕量級指針、強指針和弱指針)的實現(xiàn)原理分析 |
|