std::make_s...or_overwrite(3)
π NAME π
okay so this is the std::make_shared / std::make_shared_for_overwrite page β straight outta the C++ Standard Library manual (that's the manual name, std::make_s...or_overwrite(3), bestie, the title's just doing a little truncated slay π
).
β¨ SYNOPSIS β¨
So first things first: everything here lives in the header <memory>. That's the vibe check. π«Ά
template< class T, class... Args > (1)
shared_ptr<T> make_shared( Args&&... args );
// since C++11, T is not array
template< class T > (2)
shared_ptr<T> make_shared( std::size_t N );
// since C++20, T is U[]
template< class T > (3)
shared_ptr<T> make_shared();
// since C++20, T is U[N]
template< class T > (4)
shared_ptr<T> make_shared( std::size_t N, const std::remove_extent_t<T>& u );
// since C++20, T is U[]
template< class T > (5)
shared_ptr<T> make_shared( const std::remove_extent_t<T>& u );
// since C++20, T is U[N]
template< class T > (6)
shared_ptr<T> make_shared_for_overwrite();
// since C++20, T is not U[]
template< class T > (7)
shared_ptr<T> make_shared_for_overwrite( std::size_t N );
// since C++20, T is U[]
πΈ DESCRIPTION πΈ
the individual overloads, one at a time, no skipping π₯
- Constructs an object of type
Tand wraps it in astd::shared_ptr, usingargsas the parameter list for the constructor ofT. The object is constructed as if by the expression::new (pv) T(std::forward<Args>(args)...), wherepvis an internalvoid*pointer to storage suitable to hold an object of typeT. The storage is typically larger thansizeof(T)in order to use one allocation for both the control block of the shared pointer and theTobject. Thestd::shared_ptrconstructor called by this function enablesshared_from_thiswith a pointer to the newly constructed object of typeT.
since C++20: this overload participates in overload resolution only if T is not an array type. no exceptions, we're being picky π
- and 3. Same as (1), but the object constructed is a possibly-multidimensional array whose non-array elements of type
std::remove_all_extents_t<T>are value-initialized as if by placement-new expression::new(pv) std::remove_all_extents_t<T>(). The overload (2) creates an array of sizeNalong the first dimension. The array elements are initialized in ascending order of their addresses, and when their lifetime ends are destroyed in the reverse order of their original construction. order matters, bestie β it's giving very careful bookkeeping β¨ - and 5. Same as (2,3), but every element is initialized from the default value
u. IfUis not an array type, then this is performed as if by the same placement-new expression as in (1); otherwise, this is performed as if by initializing every non-array element of the (possibly multidimensional) array with the corresponding element fromuwith the same placement-new expression as in (1). The overload (4) creates an array of sizeNalong the first dimension. The array elements are initialized in ascending order of their addresses, and when their lifetime ends are destroyed in the reverse order of their original construction. π¦ - Same as (1) if
Tis not an array type, and (3) ifTisU[N], except that the created object is default-initialized. (yes that's different, no they are not the same thing, ik ik π) - Same as (2), except that the individual array elements are default-initialized.
In each case, the object (or individual elements if T is an array type) (since C++20) will be destroyed by p->~X(), where p is a pointer to the object and X is its type.
π PARAMETERS π
argsβ list of arguments with which an instance ofTwill be constructedNβ array size to useuβ the initial value to initialize every element of the array
π¦ RETURN VALUE π¦
A std::shared_ptr of an instance of type T. that's it. that's the whole return value. iconic π
π₯ 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. π«Ά
(since C++20) If an exception is thrown during the construction of the array, already-initialized elements are destroyed in reverse order. (she cleans up after herself, we love a responsible queen π)
π NOTES π
So this function may be used as an alternative to std::shared_ptr<T>(new T(args...)). The trade-offs are β and this is the part where you need to pay attention, ngl:
std::shared_ptr<T>(new T(args...))performs at least two allocations (one for the objectTand one for the control block of the shared pointer), whilestd::make_shared<T>typically performs only one allocation (the standard recommends, but does not require this; all known implementations do this). π one allocation, so efficient, we stan- If any
std::weak_ptrreferences the control block created bystd::make_sharedafter the lifetime of all shared owners ended, the memory occupied byTpersists until all weak owners get destroyed as well, which may be undesirable ifsizeof(T)is large. β οΈ big object + lingeringweak_ptr= sad times std::shared_ptr<T>(new T(args...))may call a non-public constructor ofTif executed in context where it is accessible, whilestd::make_sharedrequires public access to the selected constructor. π- Unlike the
std::shared_ptrconstructors,std::make_shareddoes not allow a custom deleter. π std::make_shareduses::new, so if any special behavior has been set up using a class-specificoperator new, it will differ fromstd::shared_ptr<T>(new T(args...)).- (until C++20)
std::shared_ptrsupports array types (as of C++17), butstd::make_shareddoes not. This functionality is supported byboost::make_shared. - (until C++17) code such as
f(std::shared_ptr<int>(new int(42)), g())can cause a memory leak ifggets called afternew int(42)and throws an exception, whilef(std::make_shared<int>(42), g())is safe, since two function calls are never interleaved. π₯ this one's a classic, write it down
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 testptr->weak_this.expired()in the exposition code above makes sure thatweak_thisis not reassigned if it already indicates an owner. This test is required as of C++17. bestie do not remove it, i'm serious π
π feature-test macro moment π
__cpp_lib_shared_ptr_arraysβ value201707Lβ Std (C++20) β feature: Array support ofstd::make_shared; overloads (2-5)__cpp_lib_smart_ptr_for_overwriteβ value202002Lβ Std (C++20) β feature: Smart pointer creation with default initialization (std::allocate_shared_for_overwrite,std::make_shared_for_overwrite,std::make_unique_for_overwrite); overloads (6,7)
π EXAMPLE π
Run this code, it's a whole aesthetic π
#include <iostream>
#include <memory>
#include <type_traits>
#include <vector>
struct C
{
// constructors needed (until C++20)
C(int i) : i(i) {}
C(int i, float f) : i(i), f(f) {}
int i;
float f{};
};
int main()
{
// using `auto` for the type of `sp1`
auto sp1 = std::make_shared<C>(1); // overload (1)
static_assert(std::is_same_v<decltype(sp1), std::shared_ptr<C>>);
std::cout << "sp1->{ i:" << sp1->i << ", f:" << sp1->f << " }\n";
// being explicit with the type of `sp2`
std::shared_ptr<C> sp2 = std::make_shared<C>(2, 3.0f); // overload (1)
static_assert(std::is_same_v<decltype(sp2), std::shared_ptr<C>>);
static_assert(std::is_same_v<decltype(sp1), decltype(sp2)>);
std::cout << "sp2->{ i:" << sp2->i << ", f:" << sp2->f << " }\n";
// shared_ptr to a value-initialized float[64]; overload (2):
std::shared_ptr<float[]> sp3 = std::make_shared<float[]>(64);
// shared_ptr to a value-initialized long[5][3][4]; overload (2):
std::shared_ptr<long[][3][4]> sp4 = std::make_shared<long[][3][4]>(5);
// shared_ptr to a value-initialized short[128]; overload (3):
std::shared_ptr<short[128]> sp5 = std::make_shared<short[128]>();
// shared_ptr to a value-initialized int[7][6][5]; overload (3):
std::shared_ptr<int[7][6][5]> sp6 = std::make_shared<int[7][6][5]>();
// shared_ptr to a double[256], where each element is 2.0; overload (4):
std::shared_ptr<double[]> sp7 = std::make_shared<double[]>(256, 2.0);
// shared_ptr to a double[7][2], where each double[2]
// element is {3.0, 4.0}; overload (4):
std::shared_ptr<double[][2]> sp8 = std::make_shared<double[][2]>(7, {3.0, 4.0});
// shared_ptr to a vector<int>[4], where each vector
// has contents {5, 6}; overload (4):
std::shared_ptr<std::vector<int>[]> sp9 =
std::make_shared<std::vector<int>[]>(4, {5, 6});
// shared_ptr to a float[512], where each element is 1.0; overload (5):
std::shared_ptr<float[512]> spA = std::make_shared<float[512]>(1.0);
// shared_ptr to a double[6][2], where each double[2] element
// is {1.0, 2.0}; overload (5):
std::shared_ptr<double[6][2]> spB = std::make_shared<double[6][2]>({1.0, 2.0});
// shared_ptr to a vector<int>[4], where each vector
// has contents {5, 6}; overload (5):
std::shared_ptr<std::vector<int>[4]> spC =
std::make_shared<std::vector<int>[4]>({5, 6});
}
π» Output π»
sp1->{ i:1, f:0 }
sp2->{ i:2, f:3 }
and that's where part 1 wrapsβ¦ but we're not done, bestie, part 2 is pulling up πβ¨
π See also β¨
okay bestie, here's the little family tree of related stuff β all of these are links to other pages, so go click around, it's giving "lore" π₯
constructorβ constructs newshared_ptr(public member function) π«Άallocate_sharedβ creates a shared pointer that manages a new object (function template)allocate_shared_for_overwrite(C++20) β allocated using an allocator (function template)enable_shared_from_this(C++11) β allows an object to create ashared_ptrreferring to itself (class template) πmake_unique,make_unique_for_overwrite(C++14), (C++20) β creates a unique pointer that manages a new object (function template)operator new,operator new[]β allocation functions (function)
and that's the whole page, no cap π that's literally everything β every last cross-reference included, because i would never gatekeep a shared_ptr from you π§
this one came straight from cppreference.com, dated 2024.06.10, and it's filed under std::make_s...or_overwrite(3) β like, that truncated name is genuinely sending me π but it's iconic, we respect it π
go forth and allocate, bestie, and remember: make_shared_for_overwrite for shared, make_unique_for_overwrite for unique, and always read the See also. mwah πβ¨
π¦ 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