tl;dr: The usage of
delete in normal C++ code is an anti-pattern. There are
ways of managing memory and other resources that are both more comfortable and
safer (while maintaining the same performance as manual
techniques go by the name RAII.
Let’s start with an example:
Obviously, there’s a problem: The function
dialogFoo creates a new
object on the heap using
new and uses it, but does nothing to get rid of it.
The memory and any other resources (icons, fonts, …) used by the dialog are
leaked: the operating system still thinks that they are in use and will not be
able to give them to programs (including the program containing
that really need them.
Exceptions: It’s not so simple…
The obvious fix for this is to add a
delete at the end of
This is not a good solution for two reasons: First, it is easy to forget the
delete and it makes the code longer. Second, it is incomplete: If an exception
is thrown anywhere between the
new and the
dlg is still leaked
dialogFoo is not exception-safe).
The absence of
throw does not even remotely indicate the absence of
exeptions: Even if the called member functions of
dlg never throw (which is
very unlikely for real code), there certainly is a function that might throw:
<< operator of
std::cout. It is unlikely, but someone could have called
std::cout.exceptions(std::ios::badbit) and the
program’s output could have been redirected to a write-protected file.
You would have to avoid all C++ libraries that use exceptions, including the
standard library and
std::bad_cast) to ensure complete freedom of exceptions. Let’s face it:
Unless a function (including overloaded operators) is documented not to throw
(preferrably even annotated with C++11’s
noexcept), you have to
assume that it will eventually throw an exception.
The idea of a
catch block may arise now and indeed a way to write the
function that offers the basic exception guarantee (i.e.
it does not leak resources when an exception is thrown) would be:
But this approach leads to madness: Even though this (previously) tiny function manages only one resource, the cleanup code already accounts for 6 out of 10 lines in the function’s body.
Avoiding the heap: It’s simpler!
In the case of
dialogFoo, fortunately there is a much simpler solution: Simply
new and use
Dialog directly (as a stack-allocated variable),
instead of a pointer:
Besides being leak-free, that’s even a bit simpler than the initial
example, as it doesn’t have to use
new. It also runs faster,
as stack allocation is much faster than heap allocation. In general, heap
allocation should only be used when it’s really necessary.
Sometimes though, using a stack-allocated variable is not an option, e.g. when dealing with polymorphic classes:
Luckily, the C++ standard library can help here, with so called smart pointers:
std::unique_ptr is very simple: For the most part, it acts just
like a normal pointer (supporting the
-> operators) except that it
deletes the pointee in its destructor. There is one more important difference
though: If you want to assign it from a plain pointer (as the one returned by
new in the above example), you can’t just use the assignment operator
you have to use the
reset member function. The reason for this complication is
delete is called on the
unique_ptr’s previous value and if
= was used
for that instead of
unique_ptr could not be safely used as a drop-in
replacement for a plain pointer, as it would change the code’s meaning. This
way, a compile time error is generated when you rely on a behavior that is
differs from a plain pointer’s.
Beyond memory: RAII
This idiom of wrapping all resources (be it memory like in this example, files,
network connections, database connections, font handles, window handles, or
anything other) into a stack-allocated object that frees them in its destructor
is known by the (somewhat meaningless) name RAII (Resource Acquisition
Is Initialization). Other examples of its use include the standard file stream
ifstream) that close the file
automatically or the STL collection classes (
that destroy their contained elements. In fact, probably even the
of the above example will use RAII, as we have assumed that its destructor frees
any associated fonts, windows, and other handles it used.
The deterministic destructors of C++ (in contrast to garbage collected
languages where you can never know when or if finalizers are run)
that make this idiom possible are one of the language’s key features, some call
it even the best one. Often, you will see modern C++ code having
a much smaller share of resource management boilerplate code than garbage
collected languages with their
with (Python), or
try-with-resources (Java) blocks.