SOUI中對象的生命周期管理


C++程序員最難的一環就是處理內存泄漏。

很多情況下,一個對象在一個模塊里分配了內存,忘記了釋放,或者在另一個模塊里釋放都會導致內存相關的問題。

SOUI中大部分暴露在應用層的對象都使用類似COM的引用計數來管理對象的生命周期,包含SWindow, ISkin, EventArg, SStringT, IRenderTarget, IBitmap, IAdapter以及各種擴展組件。

SOUI中引用計數的基類是:SOUI::IObfRef

namespace SOUI
{
    struct IObjRef
    {
        virtual long AddRef() PURE;

        virtual long Release() PURE;
    
        virtual void OnFinalRelease() PURE;
    };
}

 

SOUI中使用引用計數有一個簡單的原則:一個對象,誰AddRef,那也應該它來Release。

經常有人問:為什么我調用了SImageWnd::SetImage就有內存泄漏了?

用戶的代碼可能是下面這樣的:

    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(即打開代碼中被注釋的行)。

SOUI中也提供了一個智能指針來簡化這個引用計數的操作:SAutoRefPtr (2.x是CAutoRefPtr)

使用智能指針,上面代碼可以改寫為:

 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日

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM