std::shared...::shared_ptr(3)
πΈ NAME πΈ
std::shared_ptr::shared_ptr β okay bestie, this is the constructor page from the std::shared...::shared_ptr(3) man page in the C++ Standard Library. It's giving "every way to build a shared_ptr" and honestly there are like thirteen of them, so hydrate first π.
β¨ Synopsis β¨
constexpr shared_ptr() noexcept; (1)
constexpr shared_ptr( std::nullptr_t ) noexcept; (2)
template< class Y > (3)
explicit shared_ptr( Y* ptr );
template< class Y, class Deleter > (4)
shared_ptr( Y* ptr, Deleter d );
template< class Deleter > (5)
shared_ptr( std::nullptr_t ptr, Deleter d );
template< class Y, class Deleter, class Alloc > (6)
shared_ptr( Y* ptr, Deleter d, Alloc alloc );
template< class Deleter, class Alloc > (7)
shared_ptr( std::nullptr_t ptr, Deleter d, Alloc alloc );
template< class Y >
shared_ptr( const shared_ptr<Y>& r, element_type* ptr ) (8)
noexcept;
template< class Y > (8)
(since C++20)
shared_ptr( shared_ptr<Y>&& r, element_type* ptr ) noexcept;
shared_ptr( const shared_ptr& r ) noexcept; (9)
template< class Y > (9)
shared_ptr( const shared_ptr<Y>& r ) noexcept;
shared_ptr( shared_ptr&& r ) noexcept; (10)
template< class Y > (10)
shared_ptr( shared_ptr<Y>&& r ) noexcept;
template< class Y > (11)
explicit shared_ptr( const std::weak_ptr<Y>& r );
template< class Y > (12)
(removed in C++17)
shared_ptr( std::auto_ptr<Y>&& r );
template< class Y, class Deleter > (13)
shared_ptr( std::unique_ptr<Y, Deleter>&& r );
Constructs a new shared_ptr from a whole buffet of pointer types that all refer to an object to manage π«Ά.
For the purposes of the description below, a pointer type Y* is said to be compatible with a pointer type T* if either Y* is convertible to T* (since C++17) or Y is the array type U[N] and T is U cv [] (where cv is some set of cv-qualifiers). Slay, now you know the vocabulary π
.
1, 2) Constructs a shared_ptr with no managed object, i.e. an empty shared_ptr. Literally nothing in it, clean slate, no thoughts head empty β¨.
3β7) Constructs a shared_ptr with ptr as the pointer to the managed object.
For (3,4,6), Y* must be convertible to T*. (until C++17)
If T is an array type U[N], (3,4,6) do not participate in overload resolution if Y(*)[N] is an invalid type or not convertible to T*. If T is an array type U[], (3,4,6) do not participate in overload resolution if Y(*)[] is an invalid type or not convertible to T*. Otherwise, (3,4,6) do not participate in overload resolution if Y* is not convertible to T*. (since C++17)
Additionally:
- 3) Uses the delete-expression
delete ptrifTis not an array type;delete[] ptrifTis an array type (since C++17) as the deleter.Ymust be a complete type. The delete expression must be well-formed, have well-defined behavior and not throw any exceptions. This constructor additionally does not participate in overload resolution if the delete expression is not well-formed. (since C++17) - 4, 5) Uses the specified deleter
das the deleter. The expressiond(ptr)must be well formed, have well-defined behavior and not throw any exceptions. The construction ofdand of the stored deleter copied from it must not throw exceptions. Deleter must be CopyConstructible. (until C++17) These constructors additionally do not participate in overload resolution if the expressiond(ptr)is not well-formed, or ifstd::is_move_constructible_v<D>is false. (since C++17) - 6, 7) Same as (4,5), but additionally uses a copy of
allocfor allocation of data for internal use.Allocmust be an Allocator. - 8) The aliasing constructor: constructs a
shared_ptrwhich shares ownership information with the initial value ofr, but holds an unrelated and unmanaged pointerptr. If thisshared_ptris the last of the group to go out of scope, it will call the stored deleter for the object originally managed byr. However, callingget()on thisshared_ptrwill always return a copy ofptr. It is the responsibility of the programmer to make sure that thisptrremains valid as long as thisshared_ptrexists, such as in the typical use cases whereptris a member of the object managed byror is an alias (e.g., downcast) ofr.get(). For the second overload taking an rvalue,ris empty andr.get() == nullptrafter the call. (since C++20) - 9) Constructs a
shared_ptrwhich shares ownership of the object managed byr. Ifrmanages no object,*thismanages no object either. The template overload doesn't participate in overload resolution ifY*is not implicitly convertible to (until C++17) compatible with (since C++17)T*. - 10) Move-constructs a
shared_ptrfromr. After the construction,*thiscontains a copy of the previous state ofr,ris empty and its stored pointer is null. The template overload doesn't participate in overload resolution ifY*is not implicitly convertible to (until C++17) compatible with (since C++17)T*. - 11) Constructs a
shared_ptrwhich shares ownership of the object managed byr.Y*must be implicitly convertible toT*. (until C++17) This overload participates in overload resolution only ifY*is compatible withT*. (since C++17) Note thatr.lock()may be used for the same purpose: the difference is that this constructor throws an exception if the argument is empty, whilestd::weak_ptr<T>::lock()constructs an emptystd::shared_ptrin that case. - 12) Constructs a
shared_ptrthat stores and owns the object formerly owned byr.Y*must be convertible toT*. After construction,ris empty. - 13) Constructs a
shared_ptrwhich manages the object currently managed byr. The deleter associated withris stored for future deletion of the managed object.rmanages no object after the call. This overload doesn't participate in overload resolution ifstd::unique_ptr<Y, Deleter>::pointeris not compatible withT*. Ifr.get()is a null pointer, this overload is equivalent to the default constructor (1). (since C++17) IfDeleteris a reference type, it is equivalent toshared_ptr(r.release(), std::ref(r.get_deleter()). Otherwise, it is equivalent toshared_ptr(r.release(), std::move(r.get_deleter())).
When T is not an array type, the overloads (3,4,6) enable shared_from_this with ptr, and the overload (13) enables shared_from_this with the pointer returned by r.release().
π Parameters π
ptrβ a pointer to an object to manage.dβ a deleter to use to destroy the object.allocβ an allocator to use for allocations of data for internal use.rβ another smart pointer to share the ownership to or acquire the ownership from.
π¨ Exceptions π¨
- 3)
std::bad_allocif required additional memory could not be obtained. May throw implementation-defined exception for other errors. If an exception occurs, this callsdelete ptrifTis not an array type, and callsdelete[] ptrotherwise (since C++17). - 4β7)
std::bad_allocif required additional memory could not be obtained. May throw implementation-defined exception for other errors.d(ptr)is called if an exception occurs. - 11)
std::bad_weak_ptrifr.expired() == true. The constructor has no effect in this case. - 12)
std::bad_allocif required additional memory could not be obtained. May throw implementation-defined exception for other errors. This constructor has no effect if an exception occurs. - 13) If an exception is thrown, the constructor has no effects.
π Notes π
A constructor enables shared_from_this with a pointer ptr of type U* means that it determines if U has an unambiguous and accessible (since C++17) base class that is a specialization of std::enable_shared_from_this, and if so, the constructor evaluates the statement:
if (ptr != nullptr && ptr->weak_this.expired())
ptr->weak_this = std::shared_ptr<std::remove_cv_t<U>>(
*this, const_cast<std::remove_cv_t<U>*>(ptr));
Where weak_this is the hidden mutable std::weak_ptr member of std::enable_shared_from_this. The assignment to the weak_this member is not atomic and conflicts with any potentially concurrent access to the same object. This ensures that future calls to shared_from_this() would share ownership with the std::shared_ptr created by this raw pointer constructor.
The test ptr->weak_this.expired() in the exposition code above makes sure that weak_this is not reassigned if it already indicates an owner. This test is required as of C++17.
The raw pointer overloads assume ownership of the pointed-to object. Therefore, constructing a shared_ptr using the raw pointer overload for an object that is already managed by a shared_ptr, such as by shared_ptr(ptr.get()) is likely to lead to undefined behavior, even if the object is of a type derived from std::enable_shared_from_this.
Because the default constructor is constexpr, static shared_ptrs are initialized as part of static non-local initialization, before any dynamic non-local initialization begins. This makes it safe to use a shared_ptr in a constructor of any static object.
In C++11 and C++14 it is valid to construct a std::shared_ptr<T> from a std::unique_ptr<T[]>:
std::unique_ptr<int[]> arr(new int[1]);
std::shared_ptr<int> ptr(std::move(arr));
Since the shared_ptr obtains its deleter (a std::default_delete<T[]> object) from the std::unique_ptr, the array will be correctly deallocated.
This is no longer allowed in C++17. Instead the array form std::shared_ptr<T[]> should be used.
π EXAMPLE π
Bestie, this is the part where we actually see it work. Run this code:
// Run this code
#include <iostream>
#include <memory>
struct Foo
{
int id{0};
Foo(int i = 0) : id{i} { std::cout << "Foo::Foo(" << i << ")\n"; }
~Foo() { std::cout << "Foo::~Foo(), id=" << id << '\n'; }
};
struct D
{
void operator()(Foo* p) const
{
std::cout << "Call delete from function object. Foo::id=" << p->id << '\n';
delete p;
}
};
int main()
{
{
std::cout << "1) constructor with no managed object\n";
std::shared_ptr<Foo> sh1;
}
{
std::cout << "2) constructor with object\n";
std::shared_ptr<Foo> sh2(new Foo{10});
std::cout << "sh2.use_count(): " << sh2.use_count() << '\n';
std::shared_ptr<Foo> sh3(sh2);
std::cout << "sh2.use_count(): " << sh2.use_count() << '\n';
std::cout << "sh3.use_count(): " << sh3.use_count() << '\n';
}
{
std::cout << "3) constructor with object and deleter\n";
std::shared_ptr<Foo> sh4(new Foo{11}, D());
std::shared_ptr<Foo> sh5(new Foo{12}, [](auto p)
{
std::cout << "Call delete from lambda... p->id=" << p->id << '\n';
delete p;
});
}
}
And the output, iconically:
1) constructor with no managed object
2) constructor with object
Foo::Foo(10)
sh2.use_count(): 1
sh2.use_count(): 2
sh3.use_count(): 2
Foo::~Foo(), id=10
3) constructor with object and deleter
Foo::Foo(11)
Foo::Foo(12)
Call delete from lambda... p->id=12
Foo::~Foo(), id=12
Call delete from function object. Foo::id=11
Foo::~Foo(), id=11
Obsessed with how the use_count() climbing 1 β 2 and then the destructor only firing once at the end of that scope just proves the whole shared-ownership moment π
. Three constructors, three vibes β empty, shared, and custom-deleter. All slaying.
π©Ή DEFECT REPORTS π©Ή
So the following behavior-changing defect reports were applied retroactively to previously published C++ standards β like a patch note for the past π:
LWG 3548β applied to C++11. Behavior as published: the constructor fromunique_ptrcopy-constructed the deleter. Correct behavior: it move-constructs instead.
Ngl that one's a glow-up fr fr.
π SEE ALSO π
The whole friend group, bestie:
make_sharedβ creates a shared pointer that manages a new object (function template)make_shared_for_overwrite(C++20) β creates a shared pointer that manages a new object (function template)allocate_sharedβ creates a shared pointer that manages a new object allocated using an allocator (function template)allocate_shared_for_overwrite(C++20) β creates a shared pointer that manages a new object allocated using an allocator (function template)enable_shared_from_this(C++11) β allows an object to create ashared_ptrreferring to itself (class template)
Go read these next, iykyk. They're the main characters of the shared-pointer cinematic universe π₯
And that's a wrap on the whole page, bestie! π This little masterpiece lives over at http://cppreference.com, version-stamped 2024.06.10, filed under std::shared...::shared_ptr(3). Go forth and share your pointers responsibly ππ
π¦ where this page comes from
- nixpkgs unstable: stdman 2024.07.05
- opensuse-leap 16.0: stdman 2024.07.05-bp160.1.9 Β· MIT
- π girlified by deepseek-ai/DeepSeek-V4.1-Flash-1017 on : a language model's rewrite of the original, under its terms