Exceptions and Pointers
Memory management of dynamically allocated object is always an
issue. We need to make sure that alll allocated objects get
destroyed to avoid a memory leak. When exceptions enter the picture,
this becomes more of a challenge.
It's typical for a function to aquire a resource (e.g. dynamic memory),
do some processing, then release the resource as in this simple
function.
void my1stFunction( )
{
// dynamically allocate a Fred object
Fred *pFred = new Fred;
// call some functions for Fred
// more code here
// destroy the Fred object
delete pFred;
}
This code is all well and good until we learn that some member
functions of Fred throw exceptions. The problem is that
when an exception is thrown and not caught by my1stFunction,
a memory leak occurs because the statement delete pFred;
is never executed. One (not-so-elegant) solution is to delete
the Fred object in a catch block.
void myNew1stFunction( )
{
// dynamically allocate a Fred object
Fred *pFred = new Fred;
try {
// call some function of Fred
}
catch( ... ) // for all exceptions
{
delete pFred; // delete the object
throw; // rethrow to higher level
}
// destroy the Fred object
// if no exception and normal termination
delete pFred;
}
This code works, but we've duplicated some code and if more
objects are involved, more try/catch blocks are needed. The code
becomes complicated, redundant and error prone.
The solution is to use an auto_ptr
auto_ptrs
An auto_ptr is a kind of "smart pointer" provided by the C++ library.
A "smart pointer" takes ownership of the dynamically allocated memory to
which it points and frees the memory whenever the smart pointer
itself is destroyed.
The auto_ptr type is just one such "smart pointer".
When an auto_ptr gets destroyed, the object to which it points
also gets destroyed (by auto_ptr's destructor), eliminating any chance of a memory leak.
void myBest1stFunction ( )
{
// dynamically allocate a Fred object
// note the syntax
auto_ptr p(new Fred);
// call some Fred functions
// do some stuff
// no need for 'delete' because when 'p'
// goes out of scope, its destructor will
// automatically delete the Fred object
}
Note that the try/catch blocks and the delete statement
are no longer required in order to delete the memory.
No matter how the function ends, the auto_ptr will go out scope
(it's a local variable) and be destroyed, taking the Fred object with it.
Using auto_ptrs
One of the fundamental issues when pointers to dynamically allocated
memory is used is that of "ownership". By "ownership", we mean the
function/object/piece of code that is responsible for deleting the
memory to which the pointer points. We saw this earlier this semester
when we discussed copy constructors and assignment operators for
classes and the need for "deep copy" and "cloning". Smart pointers
like auto_ptr can be used in any code, not just code that
needs to handle exceptions.
Using auto_ptr is just as easy as using "regular" pointer.
Doing so properly assures that a dynamically allocated object is
owned by just one pointer and no memory leak or seg fault will occur.
Only one auto_ptr may own an object, but ownership may
be easily passed from one auto_ptr to another or to/from a regular
pointer.
The auto_ptr (and all smart pointers)
supports pointer dereferencing (using *) and
using of the arrow ( -> ), just like "regular" pointers,
but does not allow pointer arithmetic.
To use auto_ptr you must #include <memory>.
#include
void my2ndFunction( )
{
Fred* p1 = new Fred; // p1 "owns" the Fred object
auto_ptr p2( p1 ); // pass ownership to an auto_ptr
// use the auto_ptr the same way
// we'd use a regular pointer
*p2 = someOtherFred; // same as "*p1 = someOtherFred;"
p2->SomeFredFunction(); // same as "p1->SomeFredFunction();"
// use release() to take back ownership
Fred* p3 = p2.release(); // now p3 "owns" the Fred object
delete p3; // need to manually delete the Fred
// p2 doesn't own any Fred object, and so won't try
// to delete one
}
We can also have multiple auto_ptrs in the same code.
auto_ptrs support assignment which transfers ownership.
void my3rdFunction()
{
auto_ptr p1( new Fred );
auto_ptr p2;
p1->SomeFredFunction( ); // OK
p2 = p1; // p2 owns the Fred object and p1 does not
p2->SomeFredFunction( ); // OK
// watch for this pitfall
p1->SomeFredFunction( ); // error! p1 is a null pointer
// when p1 and p2 go out of scope
// p2's destructor deletes the Fred object
// p1's destructor does nothing
}
This is a short introduction to auto_ptr. There are several caveats and restrictions of which you should be aware before attempting to integrate them into your code. Check out your favorite C++ STL reference book for details.
Last Modified: Monday, 28-Aug-2006 10:16:05 EDT