Cyclic dependency主要來自reference counted物件互相持有對方,導致無法順利將其指向所指向的物件解構。其實只需要一個reference counted物件即可說明此例,只要該物件持有自己即可,接下來以此為例說明。
我們以SmartPtr來做為reference counted此物件,圖中的每個箭頭代表一個reference count。
假設有個物件內容如下:
struct Self{
SmartPtr<Self> m_pSelf;
};
假設方塊物件是SmartPtr,裡面的星號代表指向真正物件的指標,而圓形物件則是Self。當你寫下 SmartPtr

接下來你繼續寫完整行 SmartPtr



問題來了:原來唯一知道圓形物件的pSelf已經不存在了,於是沒人知道這個被new出來的圓形物件,而他的reference counter不為0,也無法降為0,因此它的destructor不會被呼叫起來!! Leak就這樣產生啦!完整的code如下,你可以自己試試看self的destructor會不會被呼叫起來(當然你得自己寫個destructor幫助你觀察):
void Test( ){
SmartPtr<Self> pSelf = new Self;
pSelf.m_pSelf = pSelf;
}
如果不知道為什會有人寫這種code,你不妨想像現在有兩個SmartPtr A跟B,其中A有個member指向B,B也有個member指向A,code如下:
void Test( ){
SmartPtr<Self> pSelfA = new self, pSelfB = new self;
pSelfA.m_pSelf = pSelfB;
pSelfB.m_pSelf = pSelfA;
}
甚至不一定要是兩個,可以是一大串,A指向B,B指到C,C指到D,……最後又指回A,這個問題又發生了。
解決方案呢?寫累了,下次再寫吧!反正就是用WeakPtr的概念,WeakPtr只會observe而不會持有一個物件,Boost::weak_ptr 或 Loki::StrongPtr (整合了strong pointer與weak pointer)都可以解決這問題。
註:這篇是從 Yahoo Blog 搬過來的,原發文時間為 2007/02/12 16:47。
沒有留言:
張貼留言