Skip to content

Smart Pointers

See also https://learn.microsoft.com/en-us/cpp/cpp/smart-pointers-modern-cpp
Note: See also https://en.cppreference.com/book/intro/smart_pointers

In modern C++, Smart Pointers are Pointers that have their own sort of memory management "technology", at cost of heap allocation. Depends, what kind of Smart Pointer, I guess.

This means that these smart pointers seem to know their scope and if they're unused, they should delete the managed object and itself. Note that the smart pointer is also an object and deletes itself as well. A unique_ptr can be re-used but will delete the managed object if the methods are used properly. e.g. swapping

It's basically like initializing a raw pointer, except that it can call delete on its own.

std::unique_ptr

std::unique_ptr<T, Deleter (optional)>

Create a unique_ptr for a defined type T, with an optional custom Deleter, e.g. if you wanted to log the deletions for debugging purposes.

It also provides methods to swap pointers out and more. See the C++ docs for more info.

A unique_ptr can be created out of an already existing pointer or through std::make_unique.

See here what happens when you provide an already existing pointer: https://godbolt.org/z/WeG39GfzK .reset(nullptr) can be used, if one wanted to



See this https://godbolt.org/z/7njs4Kdx6 which sort of shows a full comprehensive overview of std::unique_ptr itself alone.

See also https://godbolt.org/z/65Mvx876v and https://godbolt.org/z/7PsrYdWx7 for a sort of comparison for with and without std::unique_ptr.

Additionally:


Also, see this for within structs:

std::make_unique

std::make_unique can be used to directly intialize a std::unique_ptr's value with =.

Note that, if you have raw pointers in a struct, that they are still due to manual memory management, unless replaced with a Smart Pointer.

Note that std::make_unique returns a std::unique_ptr.

std::unique_ptr<int> uniquePointer = std::make_unique<int>(123);

It's better like that, instead of passing it into the constructor of std::unique_ptr variable() itself. If you see it in any example code, don't mind it but avoid actually doing that, I guess.


std::shared_ptr

Unlike std::unique_ptr, a std::shared_ptr will only delete the managed object, when there are no shared_ptr left which own that said object. This is why it's called "shared", while "unique" is limited to own the same object once across all unique_ptr, otherwise there may be unexpected issues.

See https://godbolt.org/z/vsTE9cssG and https://godbolt.org/z/fjPMnYWcT for what would happen if more than one unique_ptr would initialize from the same pointer.

See https://godbolt.org/z/xd9Tz184n and https://godbolt.org/z/YMYGK6Wh9.

std::shared_ptr that own the same object, will obviously also point at the same address. Hence why a "shared pointer".

std::make_shared

std::make_shared is used to create a shared object that can be used by multiple std::shared_ptr.

You should use std::make_shared for std::shared_ptr. If std::shared_ptr is not in the same control block, it may believe, that it is the sole owner and unexpectedly delete the object.

Note that std::make_shared returns a std::shared_ptr.

std::shared_ptr<int> sharedPointer = std::make_shared<int>(123);


std::weak_ptr

A std::weak_ptr is used to point to other std::shared_ptr without actually claiming ownership of one.

See https://godbolt.org/z/eGabaY1WG.


It's also used to break cycles, e.g. useful when having a "Node" that points to previous nodes.

For instance, you may want the parent Node to be a "weak reference", and the child node a full std::shared_ptr, so that the Node owns the child object.

For instance, in a Folder structure, Folder A is in Folder B, and Folder B owns things inside of it. However, Folder B is the parent of Folder A. Hence why Folder B should not own Folder A. Therefore a std::weak_ptr should be used.



std::move with Smart Pointers

std::move is also useful for non-copyable objects.

This here would make valuePtr not own an object when it gets moved to the other std::unique_ptr.

std::unique_ptr<int> valuePtr(new int(15));
std::unique_ptr<int> valuePtrNow(std::move(valuePtr));

See also: