Summary

Short form: We propose to add library functions that allow the
systematic use of allocators as a customisation point for dynamic allocations. The new
functions complete the following picture:

using operator {new,delete}

using allocator

Manual

T * p = new T(args...)

auto p = allocator_new<T>(alloc, args...)

delete p

allocator_delete(alloc, p)

Unique pointer

default_delete<T>

allocation_deleter<T>

make_unique<T>(args...)

allocate_unique<T>(alloc, args...)

Shared pointer

make_shared<T>(args...)

allocate_shared<T>(alloc, args...)

Long form: The standard library rarely uses
new/delete directly, but instead allows customisation of dynamic
allocation and object construction via allocators. Currently this customisation is only
available for container elements and for shared_ptr (as well as for
a few other types that require dynamically allocated memory), but not for the top-level
objects themselves.

The proposal is to complete the library facilities for
allocator-based customisation by providing a direct mechanism for creating and destroying
a dynamically stored object through an allocator, as well as a new deleter type for
unique_ptr to hold an allocator-managed unique pointee, together with the
appropriate factory function.

Example use cases

Consider an arena allocator. A vector may put its elements into the arena, but the
vector itself cannot easily be placed in the same arena. The proposed
std::allocate_unique<std::vector<T,
ScopedArenaAlloc<T>>>(arena_alloc) allows this. (Here we assume the
use of the usual alias idiom template <class T> using ScopedArenaAlloc =
std::scoped_allocator_adaptor<ArenaAlloc<T>>;).

Consider a
shared memory allocator. As in the previous example, containers will put their elements
in shared memory, but one process needs to create the container itself and place it in
shared memory. This is now possible with auto p =
std::allocator_new<std::vector<T,
ScopedShmemAlloc<T>>>(shmem_alloc). The returned pointer is
presumably an offset pointer, and its offset value needs to be communicated to the other
participating processes. The last process to use the container calls
allocator_delete(shmem_alloc, p).

Design questions

Require exact allocator or allow rebind-copying? Rebind-copying would allow taking
the original allocator by const-reference, but would incur a local allocator’s
destruction (which is not required to be noexcept).

Insert a new subsection between 20.9.8 (allocator traits) and 20.9.9 (the default allocator):

20.9.? Allocation helpers [allocator.alloc_helpers]

The function templates allocator_new and allocator_delete
create and delete objects dynamically using an allocator to provide storage and perform
construction (rather than by looking up an allocation function (3.7.4.1)).