SOUI中對象的生命週期管理

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日

相關文章
相關標籤/搜索