C++ Dynamic Memory: new, delete and Smart Pointers

Normal variables live on the stack and are removed at the end of their block. Memory which must live longer is taken from the heap (free store) with new, and must be given back with delete.

new and delete

#include <iostream>

int main() {
    int* p = new int(42);              // one int on the heap
    std::cout << *p << '\n';
    delete p;                          // give the memory back

    int* arr = new int[3]{1, 2, 3};    // an array on the heap
    std::cout << arr[0] + arr[1] + arr[2] << '\n';
    delete[] arr;                      // delete[] for arrays
}
Output

42
6

The problem: leaks

If you forget delete, the memory is lost until the program ends. This is a memory leak. If you delete two times, the program can crash. These are very common bugs.

The solution: smart pointers (C++11)

A smart pointer (in <memory>) owns the object and deletes it by itself, by RAII. You almost never write new and delete in modern C++.

unique_ptr: one owner

#include <iostream>
#include <memory>

struct Resource {
    Resource()  { std::cout << "created\n"; }
    ~Resource() { std::cout << "destroyed\n"; }
    void use()  { std::cout << "using\n"; }
};

int main() {
    {
        auto r = std::make_unique<Resource>();
        r->use();
    }                                        // destroyed here automatically
    std::cout << "after the block\n";

    auto a = std::make_unique<int>(5);
    auto b = std::move(a);                   // ownership moves, a copy is not allowed
    std::cout << (a == nullptr) << ' ' << *b << '\n';
}
Output

created
using
destroyed
after the block
1 5

shared_ptr: many owners

#include <iostream>
#include <memory>

int main() {
    auto first = std::make_shared<int>(10);
    std::cout << first.use_count() << '\n';
    {
        auto second = first;                 // a second owner
        std::cout << first.use_count() << '\n';
    }
    std::cout << first.use_count() << '\n';  // the object is deleted when the count is 0
}
Output

1
2
1

Which one?

TypeOwnersUse
std::unique_ptrOneThe default choice
std::shared_ptrMany (reference counting)When ownership is really shared
std::weak_ptrNoneLook at a shared object without owning it (breaks cycles)
raw pointer or referenceNoneOnly look at an object

Copy is not allowed for unique_ptr

#include <memory>

int main() {
    auto a = std::make_unique<int>(1);
    auto b = a;
}
Output

Copy.cpp: In function 'int main()':
Copy.cpp:5:14: error: use of deleted function 'std::unique_ptr<_Tp, _Dp>::unique_ptr(const std::unique_ptr<_Tp, _Dp>&) [with _Tp = int; _Dp = std::default_delete<int>]'
5 | auto b = a;
| ^
In file included from /usr/local/include/c++/16.2.0/memory:80,
from Copy.cpp:1:
/usr/local/include/c++/16.2.0/bits/unique_ptr.h:543:7: note: declared here
543 | unique_ptr(const unique_ptr&) = delete;
| ^~~~~~~~~~
Copy.cpp:5:14: note: use '-fdiagnostics-all-candidates' to display considered candidates
5 | auto b = a;
| ^

Note: Use std::make_unique and std::make_shared. And better: use a std::vector or a std::string instead of manual arrays, so you do not need dynamic memory at all. Next: C++ Classes and Objects.

Congratulations! Chapter Finished. Learn more about the similar topics:
Exercises & Assignments
No Content Found.
Interview Questions & Answers
No Content Found.