Difference between revisions of "cpp/memory/shared ptr/make shared"
(tweak to hopefully handle multidim arrays) |
m (probably can use remove_extent_t to name the end result of that multidimensional array recursion) |
||
Line 26: | Line 26: | ||
@1@ Constructs an object of type {{tt|T}} and wraps it in a {{lc|std::shared_ptr}} using {{tt|args}} as the parameter list for the constructor of {{tt|T}}. The object is constructed as if by the expression {{c|::new (pv) T(std::forward<Args>(args)...)}}, where {{tt|pv}} is an internal {{tt|void*}} pointer to storage suitable to hold an object of type {{tt|T}}. The storage is typically larger than {{tt|sizeof(T)}} in order to use one allocation for both the control block of the shared pointer and the {{tt|T}} object. The {{tt|std::shared_ptr}} constructor called by this function enables {{tt|shared_from_this}} with a pointer to the newly constructed object of type {{tt|T}}. {{cpp/enable_if|T is not an array type}} | @1@ Constructs an object of type {{tt|T}} and wraps it in a {{lc|std::shared_ptr}} using {{tt|args}} as the parameter list for the constructor of {{tt|T}}. The object is constructed as if by the expression {{c|::new (pv) T(std::forward<Args>(args)...)}}, where {{tt|pv}} is an internal {{tt|void*}} pointer to storage suitable to hold an object of type {{tt|T}}. The storage is typically larger than {{tt|sizeof(T)}} in order to use one allocation for both the control block of the shared pointer and the {{tt|T}} object. The {{tt|std::shared_ptr}} constructor called by this function enables {{tt|shared_from_this}} with a pointer to the newly constructed object of type {{tt|T}}. {{cpp/enable_if|T is not an array type}} | ||
− | @2,3@ Same as {{v|1}}, but the element constructed is a possibly-multidimensional array whose non-array elements of type {{tt| | + | @2,3@ Same as {{v|1}}, but the element constructed is a possibly-multidimensional array whose non-array elements of type {{tt|std::remove_extent_t<T>}} are value-initialized as if by placement-new expression {{c|::new(pv) std::remove_extent_t<T>()}}. The overload {{v|2}} creates an array of size {{tt|N}} along the first dimension. The array elements are initialized in ascending order of their addresses. |
@4,5@ Same as {{v|2,3}}, but every non-array element is initialized from the default value {{tt|u}}, as if by the same placement-new expression as in {{v|1}}. The overload {{v|4}} creates an array of size {{tt|N}} along the first dimension. The array elements are initialized in ascending order of their addresses. | @4,5@ Same as {{v|2,3}}, but every non-array element is initialized from the default value {{tt|u}}, as if by the same placement-new expression as in {{v|1}}. The overload {{v|4}} creates an array of size {{tt|N}} along the first dimension. The array elements are initialized in ascending order of their addresses. | ||
Revision as of 08:15, 2 August 2017
Defined in header <memory>
|
||
template< class T, class... Args > shared_ptr<T> make_shared( Args&&... args ); |
(1) | (since C++11) (T is not array) |
template<class T> shared_ptr<T> make_shared(std::size_t N); |
(2) | (since C++20) (T is U[]) |
template<class T> shared_ptr<T> make_shared(); |
(3) | (since C++20) (T is U[N]) |
template<class T> shared_ptr<T> make_shared(std::size_t N, const std::remove_extent_t<T>& u); |
(4) | (since C++20) (T is U[]) |
template<class T> shared_ptr<T> make_shared(const std::remove_extent_t<T>& u); |
(5) | (since C++20) (T is U[N]) |
T
and wraps it in a std::shared_ptr using args
as the parameter list for the constructor of T
. The object is constructed as if by the expression ::new (pv) T(std::forward<Args>(args)...), where pv
is an internal void*
pointer to storage suitable to hold an object of type T
. The storage is typically larger than sizeof(T)
in order to use one allocation for both the control block of the shared pointer and the T
object. The std::shared_ptr
constructor called by this function enables shared_from_this
with a pointer to the newly constructed object of type T
. This overload participates in overload resolution only if T is not an array typestd::remove_extent_t<T>
are value-initialized as if by placement-new expression ::new(pv) std::remove_extent_t<T>(). The overload (2) creates an array of size N
along the first dimension. The array elements are initialized in ascending order of their addresses.u
, as if by the same placement-new expression as in (1). The overload (4) creates an array of size N
along the first dimension. The array elements are initialized in ascending order of their addresses.Contents |
Parameters
args | - | list of arguments with which an instance of T will be constructed.
|
N | - | array size to use |
u | - | the initial value to initialize every element of the array |
Return value
std::shared_ptr of an instance of type T
.
Exceptions
May throw std::bad_alloc or any exception thrown by the constructor of T
. If an exception is thrown, the functions have no effect. If an exception is thrown during the construction of the array, already-initialized elements are destroyed in reverse order.(since C++20)
Notes
This function may be used as an alternative to std::shared_ptr<T>(new T(args...)). The trade-offs are:
- std::shared_ptr<T>(new T(args...)) performs at least two allocations (one for the object
T
and one for the control block of the shared pointer), while std::make_shared<T> typically performs only one allocation (the standard recommends, but does not require this, all known implementations do this) - If any std::weak_ptr references the control block created by
std::make_shared
after the lifetime of all shared owners ended, the memory occupied byT
persists until all weak owners get destroyed as well, which may be undesirable ifsizeof(T)
is large. - std::shared_ptr<T>(new T(args...)) may call a non-public constructor of
T
if executed in context where it is accessible, whilestd::make_shared
requires public access to the selected constructor. - Unlike the std::shared_ptr constructors,
std::make_shared
does not allow a custom deleter.
|
(until C++20) |
|
(until C++17) |
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
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));
.
The assignment to the weak_this
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 code above makes sure that weak_this
is not reassigned if it already indicates an owner. This test is required as of C++17.
Example
#include <iostream> #include <memory> void foo(const std::shared_ptr<int>& i) { (*i)++; } int main() { auto sp = std::make_shared<int>(12); foo(sp); std::cout << *sp << std::endl; }
Output:
13
See also
constructs new shared_ptr (public member function) | |
creates a shared pointer that manages a new object allocated using an allocator (function template) | |
(C++14)(C++20) |
creates a unique pointer that manages a new object (function template) |