Shared Pointer
-
std::shared_ptrwas introduced in C++11- Different instances can share the same memory allocation
- It uses reference counting
-
When a
shared_ptrobject is copied or assigned- There are no memory operations
- Instead, the reference counter is incremented
- When a copy is destroyed, the counter is decremented
- When the last copy is destroyed, the counter is equal to zero
- The allocated memory is then released
-
std::shared_ptrStructure -
std::shared_ptrhas two private data members- A pointer to the allocated memory
- A pointer to its "control block"
- The control block contains the reference counter
-
std::shared_ptris defined in<memory> -
To create a
shared_ptrobject
// Pass a pointer as the constructor argument
std::shared_ptr<int> ptr1(new int(42));
// Calling std::make_shared() is better
auto ptr2 = std::make_shared<int>(42);
Copying std::shared_ptr
-
Copy constructor
std::shared_ptr<int> ptr3 = ptr2; -
Before the copy
ptr2's reference counter has the value 1
-
After the copy
ptr2andptr3share the same memory pointer and control block- The counter in the shared control block has the value 2
std::shared_ptr Operations
shared_ptrsupports the same operations asunique_ptr- Including dereferencing
auto shptr = make_shared<int>(42);
std::cout << "shared_ptr's data is" << *shptr << '\n';
- Plus copy assignment
auto shptr2 = shptr;
std::cout << "Copied shared_ptr's data is" << *shptr2 << '\n';
std::shared_ptr<int> ptr3;
shptr3 = shptr;
std::cout << "Assigned shared_ptr's data is" << *shptr3 << '\n';
shared_ptr vs unique_ptr
unique_ptrhas the same overhead as using a traditional pointershared_ptrhas more overhead- Control block initialization
- The reference counter is updated on every copy, assignment, move operation or destructor call
- Only use
shared_ptrwhen necessary
Threads and std::shared_ptr
-
Two potential issues
-
The reference counter
- Modified by every copy, assignment, move operation or destructor call
- Conflicting accesses by concurrent Threads
-
The pointed-to data
- Threads could dereference
std::shared_ptrconcurrently - Conflicting accesses
- Threads could dereference
-
The reference counter is an atomic type
- This makes it safe to use in threaded programs
- No extra code required when copying, moving or assigning
- Adds extra overhead in single threaded programs
- Internal synchronization
-
The pointed to data is the responsibility of the programmer
- Must be protected against data races
- Concurrent accesses to the data must be synchronized
- C++20 has
std::atomic<std::shared_ptr> - External synchronization