+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);
+ 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.
+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:
+memory has already been
+allocated for the CCompound object
+because of the leave,
+there is no valid pointer for the partially-constructed CCompound object
+without a valid pointer,
+there is no way to clean up the CCompound object
+
+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.
+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().
+
+