There is a well-known problem with exceptions in C++ constructors. Only
objects that are constructed completely are deleted in C++. Usually, the
developer is supposed to take special measures against the possible memory
leaks. So let us look into what Symbian offers and what else can be done to
solve the issue.
Suppose, there is a class:
class Container
{
public:
Container
()
{
thePart1 = new Part1();
thePart2 = new Part2();
};
~Container()
{
delete thePart1;
delete thePart2;
};
private:
Part1
*thePart1;
Part2
*thePart2;
}
If object c of the Container class is being created as a local object:
void test ()
{
Container c();
…
}
and the exception arises on c
construction, then c’s destructor is not
called.
The results are that Part 1
and/or Part 2 are not deleted, and a memory leak takes place.
Symbian proposes
to push the pointer to the newly created object onto the special stack – the
so-called clean-up stack. In case of an exception, the clean-up stack is
unwinded, and every pointer on it is deleted. So we could redesign our
constructor the following way (for Symbian):
Container::Container ()
{
thePart1
= new Part1();
CleanupStack::PushL(thePart1);
thePart2
= new Part2();
CleanupStack::Pop(thePart1);
};
Of course, it works and looks better than:
Container::Container ()
{
try{
thePart1 = new Part1();
thePart2
= new Part2();
}
catch
(…)
{
delete
thePart1;
delete
thePart2;
}
};
But it could be made easier and more elegant by changing the pointers
to smart pointers:
class Container
{
public:
Container
()
{
thePart1 = new Part1();
thePart2 = new Part2();
};
~Container()
{
//
nothing to do!!
};
private:
auto_ptr<Part1>
thePart1;
auto_ptr<Part2>
thePart2;
}
Thus, we decrease the risk of memory leaks on exceptions. At the same
time, we don’t have to release our resources in the constructor. It seems like
we don’t need to use CleanupStack in Symbian at all – just develop an auto_ptr
class instead:
template<class T>
class auto_ptr
{
public:
auto_ptr
(T *p = 0): ptr(p) {}
~auto_ptr()
{delete ptr;}
private:
T
*ptr;
}