Symbian Developer Library

SYMBIAN OS V6.1 EDITION FOR C++

[Index] [Glossary] [Previous] [Next]



How to implement two-phase construction

The example code shown below illustrates the provision of cleanup stack support for CBase-derived classes, and specifically details the motivation behind using a two-phase construction strategy for creating compound objects. It presents two implementations of a CCompound class, one which uses the usual C++ construction strategy, and a second which uses two-phase construction.


Example classes

This section will use the following classes as examples.

CSimple is a simple class whose members do not refer to external resources:

class CSimple : public CBase
   {
public:
 CSimple(TInt);
 void Display();
private:
 TInt iVal;
 };

CCompound owns other objects:

class CCompound : public CBase
   {
public:
 void Display();
 ~CCompound();
  static CCompound* NewL(TInt aVal);
  static CCompound* NewLC(TInt aVal);
protected:
 CCompound(TInt aVal);
 ConstructL();
private:
 TInt iVal;
 CSimple* iChild;
 };

Note that the constructor is protected, so that CCompound objects can only be created through the public static NewL() and NewLC() functions.

[Top]


Incorrect construction allowing a memory leak

First consider what would happen if the CSimple object owned by the CCompound were allocated and constructed by the CCompound’s constructor:

CCompound::CCompound(TInt aVal)
 {
 iVal=aVal;
 iChild = new (ELeave) CSimple(aVal);
 }

The problem with this approach is that, if the new in the CCompound’s constructor leaves, then:

[Top]


Two-phase construction

The solution is to allocate the CCompound, push a pointer to the clean-up stack, and then complete its construction. Any construction which might leave must be performed after the partially-constructed object’s address has been pushed to the clean-up stack.

  1. Push the object to the clean-up stack after it has been allocated.

  2. Call the ConstructL() function to complete construction.


NewLC() example

// NewLC with two stage construction
CCompound* CCompound::NewLC(TInt aVal)
 {
 // get new, leave if can't
 CCompound* self=new (ELeave) CCompound(aVal);
 // push onto cleanup stack in case self->ConstructL leaves
 CleanupStack::PushL(self);
 // complete construction with second phase constructor
 self->ConstructL();
 return self;
 }

Now the ConstructL() function is defined instead of the C++ constructor. It performs essentially the same functions as the C++ constructor in the single-phase case:


ConstructL() example

void CCompound::ConstructL()
 {
 // NB. function may leave, as CSimple::NewL may leave
 iChild = new (ELeave) CSimple (iVal);
 }

Implement NewL() by doing a NewLC(), followed by popping the pushed pointer from the cleanup stack:


NewL() example

CCompound* CCompound::NewL(TInt aVal)
 {
 CCompound* self=NewLC(aVal);
 CleanupStack::Pop();
 return self;
 }


Note