用户操作
[即时聊天] [发私信] [加为好友]
炒炒冰激淋ID:dycwahaha
13850次访问,排名8837,好友0人,关注者1人。
dycwahaha的文章
原创 112 篇
翻译 0 篇
转载 12 篇
评论 1 篇
最近评论
psnccs:Wow gold
文章分类
收藏
    相册
    存档
    软件项目交易
    订阅我的博客
    XML聚合  FeedSky
    订阅到鲜果
    订阅到Google
    订阅到抓虾
    订阅到BlogLines
    订阅到Yahoo
    订阅到GouGou
    订阅到飞鸽
    订阅到Rojo
    订阅到newsgator
    订阅到netvibes

    原创 理解 NewL ConstructL NewLC ELeave(ZZ)收藏

    新一篇: Symbian OS 资源文件(.rss)(zz) | 旧一篇: CCoeControl(ZZ)

     

     

    转载自:http://hsany330.blog.163.com/blog/static/17681369200761981152201/

     

     

    初学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

    发表于 @ 2008年08月20日 20:15:00|评论(loading...)|收藏

    新一篇: Symbian OS 资源文件(.rss)(zz) | 旧一篇: CCoeControl(ZZ)

    评论:没有评论。

    发表评论  


    当前用户设置只有注册用户才能发表评论。如果你没有登录,请点击登录
    Csdn Blog version 3.1a
    Copyright © 炒炒冰激淋