Symbian 學習日誌(四. NewL 和 NewLC) (轉的總結)
理解 NewL ConstructL NewLC ELeave
初學Symbian開發,第一件感覺迷惑的事情是CleanupStack 第二件肯定是隨處可見的NewL,NewLC,ConstructL。
這些函式的出現依然和記憶體洩漏有關,這是一種被稱為兩步構造的機制,英文叫Two-phase Construction。
我知道C++裡面的 new 操作符實際上完成2件事,第一根據物件類的大小在堆上分配一塊記憶體並獲得指向記憶體的
指標,第二利用指標呼叫類的建構函式,最後把指標返回。
在Symbian上這樣做是有隱患的,就是當你分配好了記憶體,但是呼叫建構函式的時候程式意外退出了,這樣會造成
剛才分配的記憶體產生洩漏。只有那些放入CleanupStack的記憶體,在程式意外結束後會被釋放,new 分配的記憶體在
呼叫建構函式之前還沒有被放入CleanupStack呢。
Symbian的設計師為了解決這個問題,給所有開發者設計了一個編寫程式的定式,這就是Two-phase Construction。
具體是這樣的:
把普通的new 操作分為2個步驟來進行,第一步只分配記憶體,當分配的記憶體被放入cleanupstack後,第二步進行構造。
但是在C++裡 如何阻止編譯器的new操作不呼叫建構函式呢?這個貌似不可以。。。
於是Symbian的設計者作了個規定,類在建構函式裡不要做任何可能產生異常的操作,只能做那些絕對安全的事情,比如
簡單的變數賦值,然後提供一個名字叫 ConstructL的函式,在這個函式裡做所有類的初始化工作,當然包括那些危險
的可能導致異常的操作。
那麼 Symbian的 類構造就變成了這樣
比如 有一個叫 CFoo 的類,我想宣告一個指標 p,建立一個CFoo的物件賦給 p
CFoo *p = new(ELeave) CFoo();
CleanupStack::PushL(p);
p->ConstructL();
CleanupStack::Pop();
這樣寫是不是有點太羅嗦?每個物件都要用4條語句建立,如果是頻繁使用實在是太麻煩了。
於是Symbian的設計者又作了一個規定,每個類要實現一個NewL的static函式來完成上面的4條語句的工作
class CFoo
{
public:
static CFoo *NewL()
{
CFoo *self = new(ELeave) CFoo();
CleanupStack::PushL(self);
self->ConstructL();
CleanupStack::Pop();
return self;
}
}
有了NewL以後,呼叫CFoo的類的程式簡化了
CFoo *p = CFoo::NewL();
那麼NewLC又是什麼呢?和NewL有什麼不同?
有些類是這樣的,他們提供一些方法,需要在物件建立完成後執行,但是這些方法也是會產生異常的比如
CFoo 如果有一個方法叫 DoSomethingL()
那麼程式可以這樣寫嗎?
CFoo *p = CFoo::NewL();
p->DoSomethingL();
顯然這樣寫是有問題的正確的寫法是
CFoo *p = CFoo::NewL();
CleanupStack::PushL(p);
p->DoSomethingL();
CleanupStack::Pop();
天啊,又是4條語句,太麻煩了。要知道在NewL結尾我們剛剛把CFoo的指標從CleanupStack裡拿出來,馬上就又放了進去。
是不是可以簡化呢,那好我們再節約2條語句
NewL去掉結尾的CleanupStack::Pop();
static CFoo *NewL()
{
CFoo *self = new(ELeave) CFoo();
CleanupStack::PushL(self);
self->ConstructL();
return self;
}
呼叫去掉CleanupStack::PushL
CFoo *p = CFoo::NewL();
p->DoSomethingL();
CleanupStack::Pop();
Symbian的設計者又規定了,具有以上行為的NewL 應該叫NewLC。表示指標返回後,沒有從CleanupStack裡取出,你可以繼續呼叫一個危險的操作,在最後呼叫CleanupStack::Pop();
我發現 NewL 可以通過呼叫NewLC實現。
那麼一個符合Symbian設計師的N條規定的類應該這樣寫
class CFoo
{
public:
static CFoo *NewLC()
{
CFoo *self = new(ELeave) CFoo();
CleanupStack::PushL(self);
self->ConstructL();
return self;
}
static CFoo *NewL()
{
CFoo *self = NewLC();
CleanupStack::Pop();
return self;
}
virtual ~CFoo()
{
}
protected:
CFoo()
{
}
void ConstructL()
{
// ....
}
}
這裡注意 CFoo的建構函式不能是Public的,為了防止使用者用new 或者在棧上建立物件。
解構函式要寫成虛擬函式,這是純C++問題,不明白的去看 More Effective C++
要說明一下,以上的寫法是Symbian極力推薦的,但是不是硬性規定的,你只要保證沒有記憶體洩漏
可以不這麼寫。
我個人還是推薦這樣,這樣的程式碼寫Symbian程式的人都可以很好地理解。
最後說一下 new 之後為什麼要有一個 (ELeave)。
new操作符是被Symbian過載過了,ELeave是給new的一個引數,他的意思是告訴new當無法分配記憶體時
程式就退出。比如記憶體不足的時候。
所以我們用了ELeave的話 就不用檢查new 返回的指標了,能返回就一定是對的
如果出了錯程式就結束掉了,new根本就不會返回。
NewL NewLC 是Symbian程式標誌性的函式,所以有個Symbian開發的資源站點就叫 www.newlc.com
相關文章
- MySQL 事務、日誌、鎖、索引學習總結,MySql索引
- 學習PS、AI日誌總結 (以PS為例)AI
- MySQL的日誌總結MySql
- 【轉載】MySQL慢查詢日誌總結MySql
- 學習日誌
- 第四周學習總結
- 總結-理解和使用aix的日誌系統(zt)AI
- rsyslog日誌總結
- Docker學習總結(四)——容器間的通訊和資料卷Docker
- maven 學習總結(四)——Maven核心概念Maven
- 日誌框架學習框架
- Vipper日誌庫的學習
- 轉載的學車日誌
- 工作日誌總結二
- 工作日誌總結一
- [Mysql]日誌刷盤總結MySql
- 日誌列印的碎碎念總結
- SQL Server日誌檔案總結及日誌滿的處理SQLServer
- Web前端學習總結第四周Web前端
- JavaScript學習總結(四)function函式部分JavaScriptFunction函式
- 11.3 學習日誌
- Git 學習日誌1Git
- 【Mysql 學習】日誌的維護MySql
- 轉載 hessian學習總結
- sqlserver日誌檔案總結及充滿處理(轉)SQLServer
- logstash的安裝使用、收集json日誌、csv日誌總結JSON
- [zt] SQL Server日誌檔案總結及日誌滿的處理SQLServer
- 一個 JSer 的 Dart 學習日誌(四):非同步程式設計JSDart非同步程式設計
- ELK監控nginx日誌總結Nginx
- sql server日誌檔案總結及日誌滿的處理辦法SQLServer
- 我的MYSQL學習心得(15) : 日誌MySql
- 小白學習如何打日誌
- 蘇嵌7.9學習日誌
- 【Mysql 學習】Mysql 日誌(一)MySql
- 【轉載】IEEE754 學習總結
- springboot學習日誌(二)– thymeleaf學習Spring Boot
- 工作總結!日誌列印的11條建議
- Rust 日誌系統實踐總結Rust