C++程序員最難的一環就是處理內存泄漏。程序員
不少狀況下,一個對象在一個模塊裏分配了內存,忘記了釋放,或者在另外一個模塊裏釋放都會致使內存相關的問題。spa
SOUI中大部分暴露在應用層的對象都使用相似COM的引用計數來管理對象的生命週期,包含SWindow, ISkin, EventArg, SStringT, IRenderTarget, IBitmap, IAdapter以及各類擴展組件。指針
SOUI中引用計數的基類是:SOUI::IObfRefcode
namespace SOUI { struct IObjRef { virtual long AddRef() PURE; virtual long Release() PURE; virtual void OnFinalRelease() PURE; }; }
SOUI中使用引用計數有一個簡單的原則:一個對象,誰AddRef,那也應該它來Release。對象
常常有人問:爲何我調用了SImageWnd::SetImage就有內存泄漏了?blog
用戶的代碼多是下面這樣的:生命週期
bool SDemoSkin::SetImage(SStringW imgfile) { m_bIsColor = false; m_FilePath = imgfile; IBitmap *image = LOADIMAGE2(L"file:" + imgfile); if (image) { SetImage(image); //image->Release(); return true; } return false; }
這個問題很簡單,看一下SetImage(IBitmap*)這個方法的代碼就知道,它會本身持有這個IBitmap*對象。內存
一般這是用戶從文件或者內存加載後建立的IBitmap對象,全部SOUI對象的建立都自動調用了AddRef,所以調用它個方法的人調用完成後,再也不使用這個對象,則應該相應的調用一下Release(即打開代碼中被註釋的行)。get
SOUI中也提供了一個智能指針來簡化這個引用計數的操做:SAutoRefPtr (2.x是CAutoRefPtr)it
使用智能指針,上面代碼能夠改寫爲:
bool SDemoSkin::SetImage(SStringW imgfile) { m_bIsColor = false; m_FilePath = imgfile; SAutoRefPtr<IBitmap> image; image.Attach(LOADIMAGE2(L"file:" + imgfile)); if (image) { SetImage(image); return true; } return false; }
注:因爲LOADIMAGE2內部已經調用了AddRef,而智能指針直接賦值時會自動AddRef,所以這裏要用image.Attach來得到指針。Attach不會自動調用AddRef.
使用好IObjRef,配合上SAutoRefPtr,能夠將SOUI的內存泄漏問題下降不少。
啓程軟件 2019年10月17日