×
Namespaces

Variants
Actions

The Implications of Leaving in a Constructor

From Nokia Developer Wiki
Jump to: navigation, search
Article Metadata
Article
Created: hamishwillee (30 Mar 2011)
Last edited: hamishwillee (03 Dec 2012)

This article explains why it's a bad idea to leave in a Symbian C++ constructor, and why you shouldn't use the cleanup stack in your constructor to make your code leave-safe (use two phase construction instead!).

Contents

Why Not Leave In a Constructor?

First, let's take the simplest explanation of why it's a bad idea to leave in a constructor. Take the following line of code, which allocates an object of type CWidget on the heap:

CWidget* widget = new (ELeave) CWidget();

When it executes, a CWidget object is first allocated on the heap if there is sufficient memory available (if there is not, a leave occurs and no construction takes place). Assuming that CWidget was allocated successfully on the heap, the constructor of class CWidget is then called to initialize the object. If the constructor leaves, any other memory the constructor may have already successfully allocated will be orphaned, because the destructor is not called if an exception occurs during construction. This results in a memory leak.

Overview of Two Phase Construction

On Symbian platform, the two-phase construction idiom is most commonly used to allow initialization code that may leave to be called safely. Using two-phase construction, the CWidget class is defined as follows:

class CWidget : public CBase
{
public:
static CWidget* NewL();
static CWidget* NewLC();
~CWidget();// Must cope with partially constructed objects
private:
CWidget(); // Guaranteed not to leave
void ConstructL(); // Second phase construction code, may leave
...
};

All leaving code is removed from the constructor to a "second phase constructor" function, typically called ConstructL(). As this function is called after the object is fully constructed (and when it is safely added to the CleanupStack) the destructor is guaranteed to be called to clean up the object. A useful feature of C classes is that objects are zero-initialised on construction; so the destructor can safely call delete on member objects, whether or not they are partially constructed.

The NewL() and NewLC() static factory functions wrap up the construction code to make object creation easier for object users, and to provide an interface that is less prone to binary compatibility issues.

The above information should be familiar to most Symbian C++ developers, for whom two-phase construction for C classes is second nature. For a full review see Fundamentals of Symbian C++/Object Construction.

Why Not Use Single Phase Construction With the Cleanup Stack?

Instead of adding static factory functions, a private ConstructL() and the boilerplate code associated with two-phase construction, there seems to be no reason why you shouldn't use the cleanup stack inside the CWidget constructor instead:

CWidget::CWidget()
{
CleanupStack::PushL(this);
// Call leaving code here
CleanupStack::Pop(this);
}

Now any memory allocated to CWidget() is protected by the cleanup stack should a leave occur, thus avoiding a memory leak. It's certainly simpler to implement than the static NewL() and NewLC() factory functions, and separate, private ConstructL() method.

So why not? Consider what would happen if CWidget() was implemented as above, using the cleanup stack in place of two-phase construction.

CWidget::CWidget()
{
CleanupStack::PushL(this);
InitializeL();
CleanupStack::Pop(this);
}

If InitializeL() leaves, the following sequence occurs (see A Comparison of Leaves and Exceptions for further details):

  1. The cleanup stack 'unwinds' and destroys the object (explicitly calling CWidget::~CWidget() and then freeing the memory allocated for the object.
  2. A XLeaveException exception is created and thrown to represent the leave, the stack is unwound and exception is caught.

When an exception is thrown in a constructor, the destructor of that object is not called since the object has not yet been constructed. However, any superclass parts of the object have been constructed so their destructors are called and they are freed back to the heap. This is because C++ guarantees to call the destructor of any fully-constructed superclasses in the event of an exception.

So if CWidget derives from CGadget, (as shown below) the CGadget destructor is called twice - first by the cleanup stack and then as a result of the exception.

class CGadget : public CBase
{
public:
CGadget();
~CGadget() {delete iBuf};
private:
HBufC* iBuf;
};
 
class CWidget : public CGadget
{
public:
CWidget();
~CWidget() {};
private:
void InitializeL();
};

The second time the destructor is invoked, it is on an object that has already been destroyed. If the destructor attempts to access any member variables it causes a memory fault, which results in a USER 42 panic (“This panic is raised by a number of RHeap member functions ... when a pointer passed to these functions does not point to a valid cell.”)

In summary, using the cleanup stack in the constructor can result in double deletions. If a class derives from other classes which have explicit and implemented destructors, you must defer calling any leaving code until after the standard C++ constructor has completed. Or, put simply, just keep using two-phase construction to ensure leaving code is called after the constructor has fully executed.

Note also that while this wasn't an issue in older versions of Symbian C++ because Leaves were implemented in terms of setjmp and longjmp, it is now that C++ exceptions are used.

Summary

The two phase construction idiom should be used for object construction in order to avoid potential double deletion of superclass objects. While the issue is not a concern for all objects, using two phase construction will ensure that your code is always leave-safe.

Another reason for preferring the two-phase construction idiom is that the use of a static factory function that returns a pointer to fully instantiated object, allows the C class constructor to be kept private. This prevents accidental instantiation of C class objects on the stack, and also allows the size of the class to be modified without breaking binary compatibility (you can find out more about this in Compatibility).

Also, two-phase construction is just more intuitive. It's easier to understand what will happen if a leave occurs during object instantiation and initialization, than if you do it all in the constructor.

Further Information

Contributors

Thanks to Lauri Aalto, Will Bamberg, Tanzim Husain and Hamish Willee who provided feedback on aspects of this article, and to Simo Saminen, for initiating the discussion on the discussion forums at developer.symbian.com.

Licence icon cc-by-sa 3.0-88x31.png© 2010 Symbian Foundation Limited. This document is licensed under the Creative Commons Attribution-Share Alike 2.0 license. See http://creativecommons.org/licenses/by-sa/2.0/legalcode for the full terms of the license.
Note that this content was originally hosted on the Symbian Foundation developer wiki.

This page was last modified on 3 December 2012, at 07:06.
29 page views in the last 30 days.

Was this page helpful?

Your feedback about this content is important. Let us know what you think.

 

Thank you!

We appreciate your feedback.

×