LEAVE and TRAP, part II: NewL and NewLC
23 juill. 2004 - 08:49

At this time, I will try to show you how (and why) to create the methods NewL and NewLC. Commonly, Symbian OS classes offers these two static method implementations. A lot of classes defines and implements these two methods, and there is a reason for that...

The process used to create and define is called "two-phased construction". This process is described as a effort to prevent that a object creation throw an exception. The object construction process is divided in two-phases:
-  On the first phase, the object is instantiated (using new (ELeave), for example) and a memory chunk is reserved for that object;
-  The second phase is where the object data and member variables are initiated (ConstructL phase).

The two-phased construction is an interesting solution, because we can separately threat 2 critical phases in the object initialization. Between these two phases, we will use the CleanupStack::PushL, to guarantee that this temporary class instance would eventually be disposed and cleaned from memory. The next stage, the ConstructL method is called. The piece of code below will try to show you how to make it:

EXPORT_C CUser* CUser::NewLC( MUserStateObserver* aObserver )
{
   CUser* self = new (ELeave) CUser( aObserver );
   CleanupStack::PushL(self);
   self->ConstructL();
   return self;
}

The NewLC method is very simple: it only calls a new operator that can LEAVE (ELeave constant), pushs this temporary class instance to the Cleanup Stack, and follows with a call to ConstructL defined in this temporary instance. After that, is preconceived that the object is well initialized.

Below you will find a NewL implementation code example:

EXPORT_C CUser* CUser::NewL( MUserStateObserver* aObserver )
{
   CUser* self = new (ELeave) CUser( aObserver );
   CleanupStack::PushL(self);
   self->ConstructL();
   CleanupStack::Pop(self);
   return self;
}

Perceive a Pop() method call after ConstructL() is called. This guarantees that this variable reference was "well-initialized", and the CleanupStack already can clean its reference from heap memory space.

The code below is a optimized NewL, which uses the NewLC implementation in it. Tha main advantage from this new code is that the code is smaller than last one...

EXPORT_C CUser* CUser::NewL( MUserStateObserver* aObserver )
{
   CUser* self = NewLC( aObserver );
   CleanupStack::Pop(self);
   return self;
}

And a ConstructL example implementation:

void CUser::ConstructL()
{
        iObserver = CUserStateObserver::NewL( this );

        iName = TBufC::NewL( 100 );

        iAge = 0;

        LoadPluginsL();
}

The NewL and NewLC methods are declared as the following code (located in CUser.h):

class CUser : public CBase
{
public:
   static CUser* NewL( MUserStateObserver* aObserver );

   static CUser* NewLC( MUserStateObserver* aObserver );
.
.
.

But, the MAIN question: when should we choose between a NewL and a NewLC? What's the main difference?

I should say you that you can ALWAYS call NewL for member variables (class or instance variables), and NewLC for automatic variables (variables declared inside a method's body). It's happen because the member variables aren't immediately cleaned from CleanupStack, unless the object maintaining these members was disposed from CleanupStack space. The member variables have a longer life time, and is desired that its CleanupStack reference may be cleaned as soon as possible. The opposite occurs with the automatic variables: they will always be cleaned by CleanupStack when the method reachs the last instruction from method's body. So, if this method, containg NewLC references, can "Leave", the external trap harness will clean this automatic variables references, and pops it.

So, everytime in our code we call NewL inside a function that can LEAVE, we are wasting performance, because this object reference will be cleaned two times, one time by NewL (CleanupStack::Pop()), and another time by the TRAP harness that is related to this function call.

See you later!

Rosfran Lins Borges
Software Engineer
Nokia's Institute of Technology - Brazil

Tutorial posted juillet 23rd, 2004 by rosfranborges

Soumis par krishnaramram (non vérifié) le mar, 2006-10-24 14:44.

EXPORT_C CUser* CUser::NewLC( MUserStateObserver* aObserver ) CUser* self = new (ELeave) CUser( aObserver ); CleanupStack::PushL(self); self->ConstructL(); return self;

Suppose in my function i have:

CUser *ptrMyUser = CUSer::NewLC(/*SomeObserver*/); MyUser->SomeFunction(); CleanUpStack::PopAndDestroy(ptrMyUser);

what would happen if ConstructL( )leaves?? "return self" the next statement would not execute and "ptrMyUser" object would be NULL.PopAndDestroy(ptrMyUser)would pop and destroy an object pointed by ptrMyUser which is NUll pointer.

We still have a pointer pushed to cleanupstack, but which has not been poped and destroyed.So in such scenario are we not leaving a pointer on clean up stack???

Please clarify.


Soumis par Anonymous le ven, 2006-10-27 06:44.

Wht will happen if function leaves at ConstructL(),.......and before return self of NewLC().

CleanUpStackPopAndDestroy(),............would be poping and destroying a NULL object.Can anybody explain??


Soumis par Anonymous le mar, 2007-03-13 07:44.

Better late than never. This is wonderful explanation for such a confusing and fundamental topic on Symbian. Great work.

Soumis par murthy le sam, 2007-09-22 13:07.

If a function leaves at constructL() , You are thinking that it does not have any reference. But we are pushing the " self " into the CleanupStack before calling the constructL therefore it can be popped and destroyed. Smiling



copyright 2003-2009 NewLC SARL