Memory management in low level code has changed slowly over the years. In
traditional C code, you would allocate memory with
malloc() and release it
Some of the problems with this approach were:
malloc()might fail if the system is running low on memory, so you would have to check for a
NULLreturn and handle the error appropriately.
- you might forget to call
free(), thus leaking memory. This is especially common when there are multiple code paths, early returns and so on.
- the memory might be referred to after its release, causing subtle bugs or crashes.
- sharing the memory between threads was error-prone and relied on complex systems to avoid leaking or trashing memory.
The above code is also perfectly valid C++, albeit not exactly idiomatic.
Rather than rely on the C runtime, C++ introduced heap management into the
language itself, with the
This too is not without its issues:
- If the system is low on memory,
newcould fail and throw an exception (the default behaviour). This would require a
try/catchblock to handle the failure, otherwise the program would abort.
newcould also be configured to return
NULL, requiring an entirely different error handling strategy.
- It is generally inadvisable to mix memory allocated with
newwith memory allocated using
malloc()(as they could potentially be allocated in different heap areanas, and cause corruption).
Modern Memory Management
To drastically simplify memory management and reduce the potential for bugs, C++11 introduces several types of smart pointers:
std::unique_ptr: a pointer which is automatically freed when the pointer goes out of scope, and has a single owner at all times
std::shared_ptr: a reference-counting pointer which can be shared among multiple threads, and deletes the object when the last reference is released
std::weak_ptr: a handle which does not hold a reference, but can be materialised into a
These three smart pointer types should be able to cover the vast majority of memory management needs in a typcail application. (There will always be exceptions which need custom allocation strategies, such as high performance games, numerical processing, etc).
By using the correct smart pointer according to the desired semantics, you can virtually eliminate leaks and other common memory problems.
These are each covered in detail in their own articles below: