理解 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
本文来自CSDN博客,转载请标明出处:http://blog.csdn.net/fz_zhou/archive/2009/02/06/3865672.aspx
分享到:
相关推荐
在CMyThread的NewL或NewLC静态方法中,使用CActiveScheduler::Start来启动线程: ```cpp CMyThread* CMyThread::NewL() { CMyThread* self = new (ELeave) CMyThread; CleanupStack::PushL(self); self->...
当你创建一个对象时,通常需要使用NewL或NewLC,它们会自动管理对象的生命周期。 - 使用`Leave`和`ReLeave`来处理异常情况,这有助于避免内存泄漏。当`Leave`被调用时,它会释放之前分配的所有资源,并返回错误码。...
8. **内存管理**:Symbian有自己独特的内存管理策略,如使用NewL、NewLC等分配和释放内存。开发者必须谨慎地管理内存,防止内存泄漏。 9. **资源管理**:在Symbian中,资源(如网络连接、套接字、文件句柄等)必须...
解释`NewL`与`NewLC`的区别以及如何使用它们 **答案:** - **两阶段构造的原因:** Symbian OS采用了两阶段构造机制来防止内存泄漏。这种机制使得在构造过程中能够安全地分配和管理资源,即使构造过程中发生异常也...
- 类的构造函数`NewL`和`NewLC`负责实例化`CAudioPlayerUtility`对象,并调用`ConstructL`进行初始化。`NewL`和`NewLC`的区别在于是否将对象放在清理栈上,以确保正确地释放资源。 - `ConstructL`方法创建了一个`...
- `NewLC` 和 `NewL` 是工厂模式的实现,前者返回一个位于清理栈上的对象指针,后者则从清理栈中弹出对象并返回。 - 这两个方法都接受元素名称、符号和原子序数作为参数,并调用构造函数进行初始化。 - 这种模式...
1. **创建和初始化**:你可以通过静态函数从内存分配描述符,如NewL或NewLC,这些函数会自动为描述符分配空间。初始化描述符通常使用Fill或Copy方法,分别用于填充零或复制其他字符串。 2. **操作字符串**:描述符...
在Microsoft Visual Studio 2010 (VS2010) 中,开发人员引入了一些新的MFC(Microsoft Foundation Classes)控件,以增强Windows应用程序的界面设计和功能。这些控件扩展了MFC库,提供了更丰富的用户交互体验。...
3. **NewLC和NewL**:每个C类(非嵌套类)都需要一个`NewLC`静态函数,用于在堆上创建对象并调用`ConstructL`。`NewL`是可选的,通常基于`NewLC`实现,但不负责清理异常。 4. **静态函数声明**:`NewL()`和`NewLC()...
**2.4.1 用NewL() 和 NewLC() 实现两阶段构建** 两阶段构造是指在创建对象时先尝试分配必要的资源,然后在确认资源分配成功后再完成对象的构造。这种模式可以通过NewL()和NewLC()函数来实现。 ##### 2.5 公共错误 ...
`NewL`和`NewLC`都是两阶段构造函数,在Symbian OS中经常使用这种模式来管理内存资源。 - **~CSmsHandler**: 析构函数,用于清理`CSmsHandler`对象占用的资源。 #### 发送短信的方法 - **SendL**: 该方法用于发送...
- **知识点**: `NewLC()`和`NewL()`是Symbian OS中用于创建对象实例的重要方法。 - **详细解释**: `NewLC()`方法会先尝试分配内存,如果成功,则调用`ConstructL()`进行初始化;如果不成功,则会释放已分配的资源并...
C++类的 NewLC() 和 NewL() - **NewLC()**:这是一种创建对象的方式,用于在异常安全的情况下分配内存。它会在调用完成后清理堆栈。 - **NewL()**:另一种创建对象的方法,不清理堆栈,但提供了一种更快速的对象...
**实例**:在CExample类中,`NewLC()`和`NewL()`两个静态函数用于将两段构造过程关联起来。`NewLC()`首先使用`new(ELeave)`操作符分配对象,随后将对象指针推入清理栈,再调用`ConstructL()`方法。若`ConstructL()`...
开发者需要理解和掌握如何正确使用`New`、`NewL`、`NewLC`、`Delete`等内存操作符,以及如何使用智能指针(如`CHeapPtrBase`)来避免内存泄漏。 4. **线程与同步**:Symbian支持多线程编程,因此,理解线程同步机制...
在应用程序的构造函数中,通过`NewL()`或`NewLC()`方法创建进度条对象。例如: ```cpp iProgressBar = CEikProgressIndicator::NewLC(); ``` 接下来,设置进度条的位置和大小,通常将其添加到状态栏或者自定义...
3. **创建线程对象**:在主线程中,通过NewL()或NewLC()动态分配线程对象,并调用ConstructL()构造函数来启动线程的初始化过程。 4. **启动线程**:调用CThread的Start()函数,使线程开始执行。 Symbian线程管理...
在代码中,你需要通过NewL()或NewLC()函数创建并初始化这个控件。 3. **更新进度**: 更新进度条的方法通常是调用CProgressControl的SetProgress()函数,传入当前进度的百分比值。你可以通过一个循环或者在异步...