allocate_delete const; delete unnecessary null check
        from allocate_new; add some more design questions.allocation_deleter. Add formal wording.const from a few places where it would not have been allowed.
        Use std::to_address (introduced by P0653R2).
        Add noexcept to allocation_deleter constructors. Allow rebinding. Wording tweaks.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.
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>>;).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).To allow std::unique_ptr to use custom allocators, we first need a deleter template that stores the allocator:
The factory function is:
The type T must not be an array type. The pathological case where the
      template argument of allocation_deleter<A> is equal (up to qualification)
      to allocation_deleter<A> has to be taken into account for the purpose of
      the constructor.
Many thanks to Daniel Krügler for a thorough review and invaluable corrections of the first version from 2016, and to the members of LEWG who reviewed the draft and provided many valuable improvements in 2018.
In [memory.syn, 19.10.2], add to the synopsis:
Insert a new subsection between 20.9.8 (allocator traits) and 20.9.9 (the default allocator):
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 ([basic.stc.dynamic.allocation, 6.6.4.4.1])).
template <class T, class A, class ...Args>
          typename allocator_traits<A>::pointer
          allocator_new(A& alloc, Args&&... args);
Requires: A shall satisfy the Cpp17Allocator requirements ([allocator.requirements, 15.5.3.5]).
Effects: Let TTraits be the type allocator_traits<A>::rebind_traits<T>.
        Obtains storage for one element from a copy a
        of alloc rebound for type T by
        calling TTraits::allocate(a, 1) and constructs an object by calling
        TTraits::construct(a, to_address(p), std::forward<Args>(args)...),
        where p is the pointer obtained from the allocation. If the construction exits with an exception, the storage
        is released using TTraits::deallocate(a, p, 1).
Returns: A pointer to the obtained storage that holds the constructed object. [Note: This pointer may have a user-defined type. – end note]
Throws: Any exception thrown by TTraits::allocate or by TTraits::construct.
template <class A, class P>
        void allocator_delete(A& alloc, P p);
Requires: A shall satisfy the Cpp17Allocator requirements ([allocator.requirements, 15.5.3.5]).
        P shall satisfy the Cpp17NullablePointer requirements ([nullablepointer.requirements, 15.5.3.3]).
Requires: p was obtained from an allocator that compares
        equal to alloc, and p is dereferenceable.
Effects: Let TTraits be the type allocator_traits<A>::rebind_traits<pointer_traits<P>::element_type>.
        Uses a copy a of alloc rebound to
        the TTraits::value_type to destroy the object *p
        by calling TTraits::destroy(a, to_address(p))
        and to release the underlying storage by calling TTraits::deallocate(a, p, 1).
Insert a new subsection 19.11.1.1.? after 19.11.1.1.3 (default_delete<T[]>):
allocation_deleter<A> [unique.ptr.dltr.alloc]allocation_deleter(const A& alloc) noexcept;
Effects: Initializes a_ with alloc.
Remarks: This constructor shall not participate in overload resolution unless
        A, ignoring qualifications, is not allocation_deleter<A>.
template <class B> allocation_deleter(const allocation_deleter<B>& other) noexcept;
Effects: Initializes a_ with other.a_.
Remarks: This constructor shall not participate in overload resolution unless
        typename allocator_traits<B>::pointer is implicitly convertible to pointer.
void operator()(pointer p);
Effects: Calls allocator_delete(a_, p).
Append a new paragraph to the end of subsection 19.11.1.4 (unique_ptr creation):
template <class T, class A, class ...Args>
          unique_ptr<T, allocation_deleter<allocator_traits<A>::rebind_alloc<T>>>
          allocate_unique(A& alloc, Args&&... args)
Remarks: This function shall not participate in overload resolution unless
        T is not an array.
Returns: unique_ptr<T, allocation_deleter<allocator_traits<A>::rebind_alloc<T>>>(allocator_new<T>(alloc, std::forward<Args>(args)...), alloc).
      
Throws: Any exception thrown by allocator_new<T>.