Symbian CleanupStack工作机制解析[2]

来源:互联网 发布:av淘宝最新发布网址 编辑:程序博客网 时间:2024/05/09 05:23

Symbian CleanupStack工作机制解析[2]

      

前面一节主要描述了Symbian OS中清理栈CleanupStack的核心基础结构及工作线路,以在用户线程中创建一个CleanupStack对象为例,详细分析了CleanupStack创建、调用的内部工作机制。本节将说明CleanupStack类针对不同对象,提供的不同方法,在发生Leave时的不同动作。

Symbian OS提供用户操作清理栈的接口通过CleanupStack类展示,全部为静态方法。将对象压入清理栈的方法有CleanupStack::PushL(CBase*)CleanupStack::PushL(TAny*)CleanupStack::PushL(TCleanupItem &)三种。从方法的不同传入参数可基本看出,针对不同的对象类型,压栈方法将调用不同的PushL重载方法来实现不同对象的入栈,当然其目的不在于如何进栈,而在于当发生Leave时,之前被压入栈的对象将做不同的处理,接下去就将详细说明不同类对象Leave时的不同处理。

当对象继承自Cbase类时,将该对象压入清理栈时会调用CleanupStack::PushL(CBase*)重载方法。

class CHeapClass : public CBase

{

public:

    ~CHeapClass();

    static CHeapClass* NewL();

    static CHeapClass* NewLC();

    void FuncL();

private:

    CHeapClass();

    void ConstructL();

private:

    TUint8* iBuf;

};

 

void CheapClass:: ConstructL()

{

    ……

iBuf = new TUint8[100];

……

}

 

CheapClass:: ~CHeapClass ()

{

    if(iBuf != NULL)

       delete[] iBuf;

}

       通常,当程序中需用到指向堆对象的局部变量时,为防止内存泄露,需在调用可能发生Leave的方法前,将该对象压入当前线程的清理栈中,如下:

 

void LocalFunc()

{

       CheapClass *obj = CheapClass::NewL();

    CleanupStack::PushL(obj);

    Obj-> FuncL();

    CleanupStack::PopAndDestroy();

}

       当调用代码FuncL出现Leave或者调用CleanupStack::PopAndDestroy()时,根据清理栈机制,此时就会释放相应对象。由于之前压入的对象objCBase的派生类,该类的特点就是具有需析构函数。所以,当发生Leave时,清理栈类调用delete方法来删除该对象,delete方法相应地能正确地调用到该派生类的析构函数,这样就能完成释放该对象及该对象所占有的资源。

    对于非CBase派生类,当压栈时调用CleanupStack::PushL(TAny*)方法。此时,当发生Leave或者调用CleanupStack::PopAndDestroy()时,清理栈内部所做的工作不同于上述情况。清理栈在清理对象时,只是简单的调用User::Free()来释放该对象。该重载方法适合没有析构函数的类对象(该对象没有自己的独占资源需要释放),因为调用User::Free()方法不会导致类析构函数被调用。

    对于特殊情况,当调用出现Leave时,代码不仅仅要做简单的类对象释放,很明显上述方法都无法满足。Symbian OS中提供如CleanupClosePushLCleanupDeletePushLCleanupReleasePushL等方法,来补充适合非类对象内存释放的情况。对于这些方法的调用,其核心就是清理栈的第三种接口CleanupStack::PushL(TCleanupItem &)的应用。

       TCleanupItem(TCleanupOperation anOperation)

    当将一个TcleanupItem对象压入清理栈后,程序调用出现Leave或者调用CleanupStack::PopAndDestroy()时,在退出TRAP前,代码有机会在TcleanupItem对象中定义的TcleanupOperation方法中先得到异常清理,TcleanupOperation方法定义如下:

    typedef void(* TCleanupOperation)(TAny*)

在自定义的TcleanupOperation方法中,用户有机会对程序异常做更多复杂和自定义的异常处理,而不是简单地只调用delete方法或者User::Free()来完成内存释放功能,在该方法,用户可以同时释放内存,释放该对象所占有的Symbian资源等。

Symbian OS提供的CleanupReleasePushL()等方法,封装了其中内部工作机制,使得用户可以方便的完成相应自定义清理方法。

class RTest;

{

public :

void Release();

}

 

RTest testObj;

CleanupReleasePushL(testObj);

……  //Some Leave Func

CleanupStack::PopAndDestroy();

当调用CleanupReleasePushL(testObj)时,内部调用了工具类CleanupRelease:: PushL()方法,创建了一个TCleanupItem对象,并用对象testObjvoid Release()方法初始化TCleanupItem对象的TcleanupOperation方法,同时将该TCleanupItem压入清理栈。当程序Leave或者调用CleanupStack::PopAndDestroy()时,对象testObjvoid Release()方法将被调用,用户可在该方法中做相应的异常处理。

总结,当通过CleanupStack::PushL(CBase*)CBase派生类压入清理栈后,程序Leave时,该类的析构函数能被及时调用,能有机会释放该对象占有的内存资源;当通过CleanupStack::PushL(TAny*)方法将非CBase类对象压入清理栈后, 程序Leave时,清理栈仅简单的调用User::Free()方法释放该对象,而不会导致析构函数被调用;当通过CleanupStack::PushL(TCleanupItem &)方法将TCleanupItem对象压入清理栈后,程序Leave时,TCleanupItem对象中定义的清理函数将被调用,可完成一些复杂情况下的异常清理。

 

开发提示:

       如上节所描述,TRAP宏有较大的内存调用开销。所以,在代码中尽量控制频繁使用TRAP宏。在一些逻辑上不可分割的操作上,可利用CleanupStack::PushL(TCleanupItem &)重载方法,在程序发生Leave时,在自定义的异常处理方法中控制程序逻辑,而不采用TRAP宏判断。

原创粉丝点击