[std::unique_ptr] – [std::shared_ptr] – [std::weak_ptr] – [Example] – [Share parts of a managed object] –
For more info about smart pointers see also http://www.gerald-fahrnholz.eu/sw/display_contents.php?file_name=c11_smart_ptr.htm
std::unique_ptr
- resource is owned by single owner
- pointer cannot be shared with other clients
- unique_ptr has no copy constructor (pass as reference or use std::move to give access or use a shared_ptr)
std::shared_ptr
- resource may be owned by multiple clients
- when shared_ptr is copied an internal use count is incremented
- object is destroyed when the last client has released its shared_pointer (i.e. the use count is incremented to 0)
std::weak_ptr
- works together with a shared_ptr and its internal control block (contains the use count and the number of connected weak pointers)
- does not hold the object alive (i.e. has no use count)
- before accessing the object through a weak_ptr first try to get a valid shared_ptr (which gets its own use count) but it is possible that the object has already been deleted
- used to avoid circular references where objects A and B both hold shared_ptr instances of each other and none of them will ever be destroyed
Example
Data class with all types of shared pointers:
struct MyData
{
int num{};
double doubleVal{};
};
using MyDataUp = std::unique_ptr<MyData>;
using MyDataSp = std::shared_ptr<MyData>;
using MyDataWp = std::weak_ptr<MyData>;
Using the smart pointers:
// Pass any arguments for constructing the object
auto upData1 = std::make_unique<MyData>(42);
auto upData2 = std::make_unique<MyData>(4711, 3.14);
auto spData = std::make_shared<MyData>(4712, 3.15);
MyDataWp wpData = spData;
if (auto spAccess = wpData.lock()) // check if object is still available
{
std::cout << spAccess->doubleVal << '\n';
}
Share parts of a managed object
Assume you want to share a part of a bigger object through a shared_ptr. Of course you do not want that the part is still used by some client while the object has already been destroyed. You can make this work by returning a shared_ptr to the part which uses the regular use count of the whole object:
auto spWholeData = std::make_shared<MyData>(44, 8.77);
// aliasing constructor of shared_ptr:
auto spDoubleVal = std::shared_ptr<double>(spWholeData, &spWholeData->doubleVal);
spWholeData.reset();
// whole object is still alive and access to data member is still possible
std::cout << *spDoubleVal << '\n';
spDoubleVal.reset(); // whole object gets destroyed