symbian的清除棧

來源:互聯網
上載者:User

symbian的清除棧

symbian是c++的子集,它基於C++但不需要C++所有的強大的功能,(事實上也不可能在手機這樣的終端上實現
完整的C++所有功能).對於異常處理,symbian沒有提供c++那樣本地變數常異處理時顯示調用解構函式的架構.
Symbian用自己清除棧來完成該工作.

1.不使用清除棧的情況:
aFuntion(){
 CBar *pBar = new (ELeave) CBar;
 pBar->FooL();
 delete pBar;
}

由於FooL是一個可能"離開"(暫時用"離開"來翻譯Symbian的錯誤Leave機制)的調用,一旦發生異常離開,則
delete pBar不能被執行,因為變數pBar本身aFunction的自動變數,會自動清除,但它指向的對象就永遠留在了
堆中.經常重啟手機的使用者可能不多.

清除棧的思想是對於需要在異常離開後必須銷毀的對象放入清除棧中,一量發生"離開",則異常處理系統會負
責將棧中的對象可靠地銷毀,簡言之它是一個需要手動控制的記憶體回收行程.需要回收的對象需要手動加入,而且
只有在發生異常時才會自動銷毀,否則這些對象一直在棧中,需要手工出棧並銷毀.

最常用的模式:

aFunction(){

CBar *pBar = new (ELeave) CBar;
CleanupStack::PushL(pBar);
pBar->FooL();
CleanupStack::Pop();
delete pBar;

}
當pBar對象被構造後,立即被放入清除棧.下面pBar->FooL();調用如果出現異常離開了aFunction函數,因為清除棧

中還儲存了變數本身的副本,它和變數pBar指向同一對象,所以它能通過這個變數副本清除掉這個堆上的對象.
如果不出現異常則程式繼續向下執行:
CleanupStack::Pop();
delete pBar;
這兩句,也就是如果沒有發生異常則要手動處理棧中的對象,對於不需要清除棧來保證清除的時候主應該及時

出棧並處理.
因為 CleanupStack::Pop(); delete pBar;非常多地在一起使用,它們被合并成一個函數:
CleanupStack::PopAndDestroy(pBar);

那麼什麼樣的對象需要放入清除棧中保護呢?
如上所述,一個函數中C類的自動變數,除了這個函數中的這個本地指標外,再也沒有其它指標指向那個對象,一
旦這個指標隨異常離開函數而消失,則它所指的對象就永遠留在了堆中,這樣的指標需要進入清除棧.

對於不需要析構的T類,一般不需要放入清除棧,除非發生這樣特殊的調用:
Txx x = new (ELeave)Txx;
一般來說很少需要在堆中分配T類.所以很少發生這樣的調用.

對於R類總是和一個資源相關聯,作為自動變數時,無論是在棧中還是在堆中建立,都需要在發生異常時已經構造

的R類需要調用Close方法或reset方法,所以自動變數的R類會經常放入清除棧.

作為一個對象的成員變數沒有理由放入清除棧,而應該放在解構函式中執行delete操作.

雖然合理使用清除棧能保證發生異常時已經構造的對象被正確銷毀,但有一種情況,清除棧無能為力.即一個對象
在構造到一半時發生異常,因為沒有成功構造,當前無法放入清除棧中.那麼前一半所點用的資源就無法釋放.
由些,引用了另一個概念:二層構建

即在構造對象是第一階段只做零初始化,不構造任何實際的操作.保證不會發生離開事件,所以在構造方法中除了
零初始化沒有任何實際操作.這樣產生一個對象的引用後就可以在清除棧中儲存它的副本,然後進行第二階段的再
進行實際的構造,這樣一量發生異常清除棧中已經有了該對象的引用.可以進行必要的清除:

//第一階段構造方法:
CTest:CTest(){
 //memner = 0;
}

void CTest::ConstructL() {
 //實際需要構造的對象.
}

然後通過兩個靜態方法 NewLC和NewL來擷取執行個體:
CTest* CTest::NewLC()
{
 CTest* self = new (ELeave) CTest;  //雖然是new (ELeave)運行符,但實際根本不會離開.
 CleanupStack::PushL(self);
 self->ConstructL(); //此時如果發生異常,清除棧中已經有了self的指標副本,可以執行必要有清除.
 return self;
}
一個LC的方法說明函數可能離開但已經使用了清除棧保護,這個方法就是調用以後引用已經放入清除棧了.不需要
再做Push操作.

當然NewLC的目的是為了防止物件建構時發生異常而不能清理,一旦構造成功返回了.我們在對它的引用時不再需要
清除棧的保護,這時需要手出棧,那麼NewL就是完成這個操作的:

CTest* CTest::NewL()
{
 CTest* self = CTest::NewLC();
 CleanupStack::Pop(self);
 return self
}

所以兩階段操作可以保證對象在構造的過程中發生異常時能被正確地清理.而提供NewLC函數的類一經構造就已經在
清除棧中了.我們只需要在必要時出棧並銷毀就行了:

HBufC* welcom = CEikonEnv::Static()->AllocReadResourceLC(R_WELCOM_TEXT);
//可能離開的操作
CleanupStack::PopAndDestroy(welcom);
 

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.