This doccument illustrates two-phase construction with example code.
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.
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.
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:
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.
Push the object to the clean-up stack after it has been allocated.
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
Two-stage construction for a class could be avoided by including a CleanupStack::PushL(this) at the start of the class's C++ constructor. This would achieve the same effect as using ConstructL(). However if the class is to be used as a base class, the constructor of any classes derived from it will incur the overhead of one push and pop in the constructor called at each level in the inheritance hierarchy, rather than one pop and push in its own NewLC().
Copyright ©2010 Nokia Corporation and/or its subsidiary(-ies).
All rights
reserved. Unless otherwise stated, these materials are provided under the terms of the Eclipse Public License
v1.0.