普通指標宣告如下,
MyClass *p;
改成用 Smart pointer 如下,
sp<MyClass> p;
p 是指標 (注意不要寫成 sp<MyClass> *p; ), <XXX> 的用法是 C++ 的 template 。然後就可以用這個指標指向一個 new 出來的 object。
p = new MyClass();
而且不需要去 delete 。在 Android 中,上面的等號是經過重載的,表面上意義跟一般等號一樣,實際上的行為除了設定 sp 中的 private 成員 m_ptr,還會執行"目前物件的 incStrong" 跟"原本這個指標指向的物件的 decStrong" 等,後面會再詳述 。
sp 是一個 object,常常會把要指定給 p 的 object 直接傳給 sp 的建構式,下面列出 4.3 版的 sp 建構式。
1. sp(T* other);
2. sp(const sp<T>& other);
3. template<typename U> sp(U* other);
4. template<typename U> sp(const sp<U>& other);
(1)是最常見的,舉例如下
sp<Client> client (new Client());
會直接把 new 出來的 object assigne 到 m_ptr,m_ptr是 sp 這個 class 的 private 成員,型別是
T* m_ptr;
用來指向實際物件的位置。當你用 smart pointer 要存取Client的成員的時候,例如
client->initCheck();
實際上 -> 運算子會 return m_ptr。所以是透過 m_ptr 來執行 initCheck() 的,
m_ptr->initCheck();
接著看有沒有其他建構方式的例子。
(2) sp(const sp<T>& other); 就是把另一個在其他地方 new 好的 sp 指標,指定給目前的 sp 指標,例如
sp<const DisplayDevice> hw(getDefaultDisplayDevice());
getDefaultDisplayDevice 裡面太複雜就不分析了,有機會看能不能找到其他例子把他替換掉,整體來講這個的觀念如下
sp<Myclass> p1( new MyClass() );
sp<Myclass> p2 (p1)
補充一下,sp(const sp<T>& other) 中的 sp<T>& ,表示調用 sp 建構式時,參數 other 是以 call by reference 方式傳遞的。
(3)跟(4) 分別對應到上面兩種方式,差別在於參數中的型別是不一樣的,template<typename U>,建構時會把 U 轉型成 T,通常 U 跟 T 應該會有繼承關係。
====================================================================
那 sp 是如何做到自動釋放記憶體呢? 答案在 RefBase 這個 object 中,每當 object 透過 sp 來引用的時候,都會執行 incStrong() 這個 RefBase 的成員,incStrong會把引用計數 mStrong 加 1,然後如果是第一次被引用,還會順便執行 onFirstRef(),
反之,當物件不在被引用時,例如 client = NULL時,會執行 decStrong 來把引用計數 mStrong 減 1,如果 mStrong 變為 0,就會執行 delete 把物件存記憶體釋放,藉此達到自動釋放的功能。
所以,注意啦!所有要用到 smart pointer 的類別,都必須繼承自 RefBase 或 LightRefBase。例如上例的Client,慢慢追你會追到他就是繼承自 RefBase 。
class Client : public BnSurfaceComposerClient
class BnSurfaceComposerClient: public BnInterface<ISurfaceComposerClient>
class BnInterface : public INTERFACE, public BBinder
class ISurfaceComposerClient : public IInterface
class IInterface : public virtual RefBase
如上,包很厚。
注:Client 這個類別定義在\frameworks\native\services\surfaceflinger\Client.h
========================================================================
wp 的觀念基本上跟 sp 一樣,但要用 wp 的 object 一定得是繼承自 RefBase。
而 wp 的引用計數是 mWeak,當 wp 被建構或解構時分別會呼叫 incWeak() 跟 decWeak() 來改變引用計數。另外 sp 在 incStrong (decStrong) 執行時也會呼叫 incWeak (decWeak)。這個部分在觀念上有點像是 sp 是 wp 的 superset。但也不能完全這樣講,因為有些 wp 的運算 sp 也不能直接使用的樣子。
wp 不能直接存取所指物件的成員,如果要存取所指物件的成員,需要透過 promote() 將 wp 升級為 sp。例如:
sp<A> p1 ;
wp<A> p2 ( new A());
p1 = p2.promote();
A->member();
wp 只重載比較運算子 (==、 != 、 >=、 <= 等),所以只能透過 wp 來比較兩個物件 (上段講的sp 不能說完全是 wp 的 superset 就是這裡,我從程式看起來似乎 sp 無法直接使用這些比較運算)。
========================================================================
RefBase 提供 extendObjectLifetime(int32_t mode); 讓使用者改變物件的生命週期,決定何時要 delete 物件, 參數 mode 的值可以如下定義:
enum {
OBJECT_LIFETIME_STRONG = 0x0000, // mStrong 為 0 時 delete 物件
OBJECT_LIFETIME_WEAK = 0x0001, // mWeak 為 0 時 delete 物件
OBJECT_LIFETIME_MASK = 0x0001 //
};
所以當你設定為 OBJECT_LIFETIME_WEAK 時,表示就算只有 wp ,物件還是不會被刪除。會保留到當連 wp 都沒有的時候才會 delete 掉物件。至於這個使用的時機跟目的該怎麼解釋,目前我還不甚了解,改天有看到例子再補。
而 wp 的引用計數是 mWeak,當 wp 被建構或解構時分別會呼叫 incWeak() 跟 decWeak() 來改變引用計數。另外 sp 在 incStrong (decStrong) 執行時也會呼叫 incWeak (decWeak)。這個部分在觀念上有點像是 sp 是 wp 的 superset。但也不能完全這樣講,因為有些 wp 的運算 sp 也不能直接使用的樣子。
wp 不能直接存取所指物件的成員,如果要存取所指物件的成員,需要透過 promote() 將 wp 升級為 sp。例如:
sp<A> p1 ;
wp<A> p2 ( new A());
p1 = p2.promote();
A->member();
wp 只重載比較運算子 (==、 != 、 >=、 <= 等),所以只能透過 wp 來比較兩個物件 (上段講的sp 不能說完全是 wp 的 superset 就是這裡,我從程式看起來似乎 sp 無法直接使用這些比較運算)。
========================================================================
RefBase 提供 extendObjectLifetime(int32_t mode); 讓使用者改變物件的生命週期,決定何時要 delete 物件, 參數 mode 的值可以如下定義:
enum {
OBJECT_LIFETIME_STRONG = 0x0000, // mStrong 為 0 時 delete 物件
OBJECT_LIFETIME_WEAK = 0x0001, // mWeak 為 0 時 delete 物件
OBJECT_LIFETIME_MASK = 0x0001 //
};
所以當你設定為 OBJECT_LIFETIME_WEAK 時,表示就算只有 wp ,物件還是不會被刪除。會保留到當連 wp 都沒有的時候才會 delete 掉物件。至於這個使用的時機跟目的該怎麼解釋,目前我還不甚了解,改天有看到例子再補。
沒有留言:
張貼留言