std::allocate_shared, std::allocate_shared_for_overwrite

From cppreference.com
< cpp‎ | memory‎ | shared ptr
Memory management library
(exposition only*)
Uninitialized memory algorithms
(C++17)
(C++17)
(C++17)
(C++20)
Constrained uninitialized
memory algorithms
(C++20)
C Library

Allocators
(C++11)
(C++11)
Memory resources
Garbage collection support
(C++11)(until C++23)
(C++11)(until C++23)
(C++11)(until C++23)
(C++11)(until C++23)
(C++11)(until C++23)
(C++11)(until C++23)
Uninitialized storage
(until C++20*)
(until C++20*)
(until C++20*)
Explicit lifetime management
Defined in header <memory>
template < class T, class Alloc, class... Args >
shared_ptr<T> allocate_shared( const Alloc& alloc, Args&&... args ) ;
(1) (since C++11)
(T is non-array)
template < class T, class Alloc >
shared_ptr<T> allocate_shared( const Alloc& alloc, std::size_t N ) ;
(2) (since C++20)
(T is U[])
template < class T, class Alloc >
shared_ptr<T> allocate_shared( const Alloc& alloc ) ;
(3) (since C++20)
(T is U[N])
template < class T, class Alloc >

shared_ptr<T> allocate_shared( const Alloc& alloc, std::size_t N,

const std::remove_extent_t <T> & u ) ;
(4) (since C++20)
(T is U[])
template < class T, class Alloc >

shared_ptr<T> allocate_shared( const Alloc& alloc,

const std::remove_extent_t <T> & u ) ;
(5) (since C++20)
(T is U[N])
template < class T, class Alloc >
shared_ptr<T> allocate_shared_for_overwrite( const Alloc& alloc ) ;
(6) (since C++20)
(T is not U[])
template < class T, class Alloc >
shared_ptr<T> allocate_shared_for_overwrite( const Alloc& alloc, std::size_t N ) ;
(7) (since C++20)
(T is U[])
1) Constructs an object of type 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(v) (until C++20) std::allocator_traits <A2> :: construct (a, pv, v) (since C++20) , where pv is an internal void* pointer to storage suitable to hold an object of type T and a is a copy of the allocator rebound to std::remove_cv_t<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. All memory allocation is done using a copy of alloc, which must satisfy the Allocator
2,3) Same as (1), but the object constructed is a possibly-multidimensional array whose every non-array element is initialized as if by the expression std::allocator_traits <A2> :: construct (a2, pv) where a2 of type A2 is the copy of the allocator rebound to manage objects of type std::remove_cv_t < std::remove_all_extents_t <T>> . The overload (2) creates an array of size N
4,5) Same as (2,3), but the elements of the array are initialized from the default value u. If std::remove_extent_t<T> is not itself an array type, then this is performed as if by the same allocator expression as in (1), except that the allocator is rebound to the std::remove_cv_t < std::remove_all_extents_t <T>> . Otherwise, this is performed as if by initializing every non-array element of the (possibly multidimensional) array with the corresponding element from u using the same allocator expression as in (1), except that the allocator is rebound to the type std::remove_cv_t < std::remove_all_extents_t <T>> . The overload (4) creates an array of size N
6) Same as (1) if T is not an array type and (3) if T is U[N], except that the created object is default-initialized
7) Same as (2), except that the individual array elements are default-initialized

For allocate_shared, the object (or the individual array elements for (2-5))(since C++20) are destroyed via the expression std::allocator_traits <A2> :: destroy (a, p) , where p is a pointer to the object and a is a copy of the allocator passed to allocate_shared

For allocate_shared_for_overwrite, the object (or individual elements if T is an array type) will be destroyed by p->~X(), where p is a pointer to the object and X

(since C++20)

Parameters

alloc - the Allocator to use
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

Can throw the exceptions thrown from Alloc::allocate() or from the constructor of T. If an exception is thrown, (1) has 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

Like std::make_shared, this function typically performs only one allocation, and places both the T object and the control block in the allocated memory block (the standard recommends but does not require this, all known implementations do this). A copy of alloc

Unlike the std::shared_ptr constructors, std::allocate_shared does not accept a separate custom deleter: the supplied allocator is used for destruction of the control block and the T

std::shared_ptr supports array types (as of C++17), but std::allocate_shared does not. This functionality is supported by boost::allocate_shared

(until C++20)

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

The test ptr-> weak_this .expired() in the code above makes sure that weak_this

Feature-test macro Value Std Feature
__cpp_lib_smart_ptr_for_overwrite 202002L (C++20) 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

#include <cstddef>
#include <iostream>
#include <memory>
#include <memory_resource>
#include <vector>
 
class Value
{
    int i;
 
public:
    Value(int i) : i(i) { std::cout << "Value(), i = " << i << '\n'; }
    ~Value() { std::cout << "~Value(), i = " << i << '\n'; }
    void print() const { std::cout << "i = " << i << '\n'; }
};
 
int main()
{
    // Create a polymorphic allocator using the monotonic buffer resource
    std::byte buffer[sizeof(Value) * 8];
    std::pmr::monotonic_buffer_resource resource(buffer, sizeof(buffer));
    std::pmr::polymorphic_allocator<Value> allocator(&resource);
 
    std::vector<std::shared_ptr<Value>> v;
 
    for (int i{}; i != 4; ++i)
        // Use std::allocate_shared with the custom allocator
        v.emplace_back(std::allocate_shared<Value>(allocator, i));
 
    for (const auto& sp : v)
        sp->print();
 
} //< All shared pointers will automatically clean up when they go out of scope.

Output:

Value(), i = 0
Value(), i = 1
Value(), i = 2
Value(), i = 3
i = 0
i = 1
i = 2
i = 3
~Value(), i = 0
~Value(), i = 1
~Value(), i = 2
~Value(), i = 3

See also

constructs new shared_ptr
(public member function)
creates a shared pointer that manages a new object
(function template)