Symbian
Symbian Developer Library

SYMBIAN OS V9.4

Feedback

[Index] [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.

[Top]


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);
    void 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, for example:

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 object first, 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 CCompound 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 creating a new CSimple object
    // may leave.
    iChild = new (ELeave) CSimple (iVal);  
    }

NewL() example

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

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

Note