伯乐共勉

讨论。NET专区
  博客园  :: 首页  :: 新随笔  :: 联系 :: 订阅 订阅  :: 管理

Symbian OS 开发初级手册 6 CleanupStack and Two-phase

Posted on 2007-02-09 17:34  伯乐共勉  阅读(172)  评论(0编辑  收藏  举报
在创建实例的时候Symbian C++使用 new (ELeave) 来代替普通的 new , 比如:
CBar *pBar = new (ELeave) CBar;

  这个用法是考虑到手机特殊的属性:内存一般较小, 经常会有内存不足的情况出现。 在pc上如果内存不足我们就会退出程序, 但是在手机不能那样频繁的退出, 所以内存不足被划分为异常, 需要离开.  下面这个函数就会在内存不足的时候在A行离开: 

void FooBarL()
  {
  CBar *pBar = new (ELeave) CBar;  //A
  User::LeaveIfError(pBar->Foo());  //B
  delete pBar;     //C
  }

    离开 作为异常处理的机制, 存在着一个问题。如果上面这个程序在B行Foo()返回了一个错误值,就会在那一行离开,但是系统为pBar指针分配的内存 也就泄漏了。为了解决这个问题, Symbian 程序中频繁使用CleanupStack(清洁栈). 它的典型使用方式如下:

void FooBarL()
  {
  CBar *pBar = new (ELeave) CBar;  //A

  CleanupStack::PushL(pBar);
  User::LeaveIfError(pBar->Foo());  //B
  CleanupStack::Pop();

  delete pBar;     //C
  }

    他的作用就是, 在B行之前, 把pBar指针放到清洁栈上, 一旦B行离开了,清洁栈就会自动删除pBar回收内存, 如果B行顺利通过, 就可以通过pop把pBar拿下来了。

   CleanupStack 有效地解决了这个潜在的内存泄漏问题, 但是这个方法在一个特殊的情况下不适用。 那就是如果一个类的构建函数离开, 那么new 为它分配的内存就会泄漏。 (构建的顺序是:系统分配内存,然后运行构建函数)

    这个问题就导入了下一个概念:two-phase construction (二层构建)
  
   我们的目标是:构建函数在任何情况下不可以离开! 要实现它就必须:
      1。 不在构建函数里使用任何L函数
      2。 不在构建函数里分配内存
     
    凡是需要以上两个操作的都放到第二层构建函数中:ConstructL. 要把两层构建结合起来,我们需要另一个静态函数,一般为NewL或者 NewLC. L大家都知道代表离开,C代表清洁栈, 下面会详细讲解NewLC的方便之处。(在这里向大家推荐一个很不错的英文Symbian 资料网 站:www.newlc.com :)
二层构建的基本模式就是:

CHelloWorldBasicAppView* CHelloWorldBasicAppView::NewL(const TRect& aRect)
    {
    CHelloWorldBasicAppView* self = CHelloWorldBasicAppView::NewLC(aRect);
    CleanupStack::Pop(self);
    return self;
    }

CHelloWorldBasicAppView* CHelloWorldBasicAppView::NewLC(const TRect& aRect)
    {
    CHelloWorldBasicAppView* self = new (ELeave) CHelloWorldBasicAppView; 
    CleanupStack::PushL(self);
    self->ConstructL(aRect);
    return self;
    }

void CHelloWorldBasicAppView::ConstructL(const TRect& aRect)
    {
    // Create a window for this application view
    CreateWindowL();

    // Set the windows size
    SetRect(aRect);

    // Activate the window, which makes it ready to be drawn
    ActivateL();
    }

    先看NewLC函数, 它创建一个CHelloWorldBasicAppView的实例, 然后把他放在清洁栈上,然后调用它的第二层构建函数(可以离 开的), 然后并没有把实例从清洁栈上取下就返回了。这样的好处就是如果我们用NewLC创建一个对象,然后调用它的可以离开的函数就不必把它放到清洁栈 上,因为它已经在上面了。NewL的功能和NewLC 是一样的,只是在返回实例前把它取下清洁栈。一般的C类都提供NewL,不是所有的C类都会提供 NewLC.

   使用清洁栈需要注意:
      1. 成员变量一般不需要放在清洁栈上, 因为当执行可离开的成员函数时,它们所在的类的实例本身就应该放在清洁栈上。 所有的成员变量所占的资源都和此实例共存亡。