2014年1月2日 星期四

Android 4.3 sp<> 與 wp<> 、Smart Pointer、紀錄

Google Android Smart Pointer 會有很多相關的知識可以參考,這邊只列一些簡單的用法跟注意事項。

普通指標宣告如下,

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 掉物件。至於這個使用的時機跟目的該怎麼解釋,目前我還不甚了解,改天有看到例子再補。














沒有留言:

張貼留言