What is the Heap
beginner
c++11
memory
All variables in C++ use a portion of the memory of your computer.
C++ has two basic forms of memory: the stack and the heap.
The heap is where non-local (but not global) variables are stored in memory.
Non-local here means heap variables are not tied to scopes unlike stack variables.
The heap is intertwined with pointers and in fact cannot be used without them.
To create a variable “on the heap” in C++ we use the new
keyword which returns a pointer.
To destroy a variable on the heap in C++ we use the delete
keyword which accepts one pointer.
Here’s an example:
#include <iostream> int main() { int* a = new int(5); std::cout << "*a: " << *a << " a: " << a << "\n"; delete a; }
*a: 5 a: 0x6000018b8000
Manual Memory Management
C++ manages coordinating with the operating system to create the heap, manage its size, and place variables when you call new
. However, explicit management of heap variables is necessary in your program and is not automatic in C++.
C++ is well known for requiring manual memory management and it’s all because of the heap.
While technically correct it’s no the full story.
There are many tools in C++’s Standard Library to help programmers with direct heap management such as std::unique_ptr
and std::shared_ptr
.
Additionally, many objects in C++ such as std::vector
and std::unordered_map
manage the memory they own by calling delete
in their destructors when needed.
You can do this as well with your own objects and you should!
Using destructors and objects on the stack allows other code to not need to worry about calling new
and delete
.
Here’s an example:
#include <iostream> // Create a single int on the heap class HeapInt { public: explicit HeapInt(int i) { std::cout << "new int\n"; i_ = new int(i); } ~HeapInt() { std::cout << "delete int\n"; delete i_; } int& value() { return *i_; } private: int* i_; }; int main() { HeapInt a(5); std::cout << "a.value(): " << a.value() << "\n"; { HeapInt b(7); std::cout << "b.value(): " << b.value() << "\n"; } }
new int a.value(): 5 new int b.value(): 7 delete int delete int
Memory Leaks
C++’s heap is where memory leaks happen.
A memory leak is when your program has allocated memory from the heap by calling new
but then doesn’t call delete
before all pointers to that memory go away.
When this happens the heap memory becomes unreachable and there’s no way for your program to get a pointer to it again.
If this happens often enough while your program is running eventually your operating system will refuse to provide more memory when calling new
and your program will likely crash.
Unfortunately when calling new
it can be easy to miss calling delete
when the code is so complex that it’s difficult to understand all the possible paths it could take.
Here’s an example of what leaking memory looks like:
#include <iostream> void foo(int i) { int* a = new int(i); std::cout << "*a: " << *a << " a: " << a << "\n"; // LEAK! } int main() { for (int i = 0; i < 5; i++) { foo(i); } }
*a: 0 a: 0x6000031d4000 *a: 1 a: 0x6000031d0000 *a: 2 a: 0x6000031d0010 *a: 3 a: 0x6000031d0020 *a: 4 a: 0x6000031d0030
Thankfully there’s many tools to help with not leaking in the first place in the C++ Standard Library. Outside the language itself there’s developer tools for catching and fixing memory leaks that do happen.
std::unique_ptr
andstd::shared_ptr
are both designed to own pointers to heap memory and call delete when appropriate.std::vector
manages contiguous arrays of data.std::unordered_map
manages key-value pairs of data.- Visual Studio has the Memory Usage tool and special hooks in its C++ library.
- Xcode has Instruments.
- GCC and Clang both have Address Sanitizer.
- The open source tool Valgrind can also catch leaks.