In modern C++, std::shared_ptr
is a smart pointer that manages shared ownership of a dynamically allocated object. It is part of the C++ Standard Library’s memory header.
Table of Contents
Shared pointers keep track of how many objects own a particular resource and automatically delete the resource when there are no owners left. However, if not used carefully, std::shared_ptr
can lead to problems such as double-deletion, dangling pointers, and memory leaks.
Let’s discuss these problems one by one,
Avoiding creating multiple shared_ptr with same Raw Pointer
Creating multiple std::shared_ptr
objects from the same raw pointer can lead to undefined behavior such as double-deletion or dangling pointers. Let’s see an example
#include <iostream> #include <memory> int main() { int* rawPtr = new int(42); std::shared_ptr<int> ptr1(rawPtr); std::shared_ptr<int> ptr2(rawPtr); // Problematic! // When ptr2 goes out of scope, it will delete rawPtr. // Then ptr1 will be left with a dangling pointer. }
This kind of code will crash your application. Let’s see what is happening in this code,
rawPtr
is a raw pointer that points to an integer allocated on the heap.ptr1
is a shared pointer that takes ownership of the integer.ptr2
is another shared pointer incorrectly given ownership of the same integer.- When
ptr2
goes out of scope, it deletes the integer.ptr1
is now a dangling pointer. - When
ptr1
goes out of scope, it will try to delete the already deleted integer, leading to a crash.
Avoiding Creating Smart Pointers with Stack memory
Shared pointers are designed to manage dynamic memory (allocated on the heap). When a std::shared_ptr
is created with a pointer to an object on the stack, it leads to undefined behavior.
Example of Incorrect Usage:
Frequently Asked:
#include <iostream> #include <memory> int main() { int x = 12; std::shared_ptr<int> ptr(&x); // Problematic! // ptr will try to delete memory it does not own when going out of scope. }
This kind of code will crash your application. Let’s see what is happening in this code,
x
is a stack-allocated integer.ptr
is a shared pointer that incorrectly attempts to take ownership ofx
.- When
ptr
goes out of scope, it will calldelete
on a stack-allocated variable, causing a crash.
Recommended Practices for Smart Pointers in C++
Using make_shared
To avoid these issues, it is recommended to use std::make_shared
. This function template enables the creation of std::shared_ptr
objects without directly passing raw pointers, ensuring safe memory allocation and deallocation.
Correct Usage with make_shared:
#include <iostream> #include <memory> int main() { auto ptr1 = std::make_shared<int>(42); std::shared_ptr<int> ptr2(ptr1); // Copy of ptr1, shares ownership. // Both ptr1 and ptr2 co-own the memory safely. // Memory will be automatically deleted when the last shared_ptr is destroyed. }
Advantages of make_shared
- It creates a
shared_ptr
in a safe manner, ensuring there is only one owner for the newly allocated memory. - It is more efficient because it performs a single heap allocation for the object and the control block used by the
shared_ptr
. - It prevents the creation of shared pointers to stack memory because
make_shared
always allocates memory on the heap.
Summary
std::shared_ptr
is a powerful tool for automatic memory management in C++. It is crucial to follow best practices like using std::make_shared
and avoiding sharing raw pointers between multiple shared_ptr
instances. By doing so, you ensure safe ownership semantics and prevent common errors like double-deletion and dangling pointers that can lead to crashes or undefined behavior. Remember that smart pointers are designed to make your code safer and more robust, but they still require careful use.
Good tips, thanks!