23 General utilities library [utilities]

23.13 Class template scoped_­allocator_­adaptor [allocator.adaptor]

23.13.1 Header <scoped_­allocator> synopsis [allocator.adaptor.syn]

  // scoped allocator adaptor
  template <class OuterAlloc, class... InnerAlloc>
    class scoped_allocator_adaptor;
  template <class OuterA1, class OuterA2, class... InnerAllocs>
    bool operator==(const scoped_allocator_adaptor<OuterA1, InnerAllocs...>& a,
                    const scoped_allocator_adaptor<OuterA2, InnerAllocs...>& b) noexcept;
  template <class OuterA1, class OuterA2, class... InnerAllocs>
    bool operator!=(const scoped_allocator_adaptor<OuterA1, InnerAllocs...>& a,
                    const scoped_allocator_adaptor<OuterA2, InnerAllocs...>& b) noexcept;

The class template scoped_­allocator_­adaptor is an allocator template that specifies the memory resource (the outer allocator) to be used by a container (as any other allocator does) and also specifies an inner allocator resource to be passed to the constructor of every element within the container. This adaptor is instantiated with one outer and zero or more inner allocator types. If instantiated with only one allocator type, the inner allocator becomes the scoped_­allocator_­adaptor itself, thus using the same allocator resource for the container and every element within the container and, if the elements themselves are containers, each of their elements recursively. If instantiated with more than one allocator, the first allocator is the outer allocator for use by the container, the second allocator is passed to the constructors of the container's elements, and, if the elements themselves are containers, the third allocator is passed to the elements' elements, and so on. If containers are nested to a depth greater than the number of allocators, the last allocator is used repeatedly, as in the single-allocator case, for any remaining recursions. [Note: The scoped_­allocator_­adaptor is derived from the outer allocator type so it can be substituted for the outer allocator type in most expressions. end note]

namespace std {
  template <class OuterAlloc, class... InnerAllocs>
    class scoped_allocator_adaptor : public OuterAlloc {
  private:
    using OuterTraits = allocator_traits<OuterAlloc>; // exposition only
    scoped_allocator_adaptor<InnerAllocs...> inner;   // exposition only
  public:
    using outer_allocator_type = OuterAlloc;
    using inner_allocator_type = see below;

    using value_type           = typename OuterTraits::value_type;
    using size_type            = typename OuterTraits::size_type;
    using difference_type      = typename OuterTraits::difference_type;
    using pointer              = typename OuterTraits::pointer;
    using const_pointer        = typename OuterTraits::const_pointer;
    using void_pointer         = typename OuterTraits::void_pointer;
    using const_void_pointer   = typename OuterTraits::const_void_pointer;

    using propagate_on_container_copy_assignment = see below;
    using propagate_on_container_move_assignment = see below;
    using propagate_on_container_swap            = see below;
    using is_always_equal                        = see below;

    template <class Tp>
      struct rebind {
        using other = scoped_allocator_adaptor<
          OuterTraits::template rebind_alloc<Tp>, InnerAllocs...>;
      };

    scoped_allocator_adaptor();
    template <class OuterA2>
      scoped_allocator_adaptor(OuterA2&& outerAlloc,
                               const InnerAllocs&... innerAllocs) noexcept;

    scoped_allocator_adaptor(const scoped_allocator_adaptor& other) noexcept;
    scoped_allocator_adaptor(scoped_allocator_adaptor&& other) noexcept;

    template <class OuterA2>
      scoped_allocator_adaptor(
        const scoped_allocator_adaptor<OuterA2, InnerAllocs...>& other) noexcept;
    template <class OuterA2>
      scoped_allocator_adaptor(
        scoped_allocator_adaptor<OuterA2, InnerAllocs...>&& other) noexcept;

    scoped_allocator_adaptor& operator=(const scoped_allocator_adaptor&) = default;
    scoped_allocator_adaptor& operator=(scoped_allocator_adaptor&&) = default;

    ~scoped_allocator_adaptor();

    inner_allocator_type& inner_allocator() noexcept;
    const inner_allocator_type& inner_allocator() const noexcept;
    outer_allocator_type& outer_allocator() noexcept;
    const outer_allocator_type& outer_allocator() const noexcept;

    pointer allocate(size_type n);
    pointer allocate(size_type n, const_void_pointer hint);
    void deallocate(pointer p, size_type n);
    size_type max_size() const;

    template <class T, class... Args>
      void construct(T* p, Args&&... args);
    template <class T1, class T2, class... Args1, class... Args2>
      void construct(pair<T1, T2>* p, piecewise_construct_t,
                     tuple<Args1...> x, tuple<Args2...> y);
    template <class T1, class T2>
      void construct(pair<T1, T2>* p);
    template <class T1, class T2, class U, class V>
      void construct(pair<T1, T2>* p, U&& x, V&& y);
    template <class T1, class T2, class U, class V>
      void construct(pair<T1, T2>* p, const pair<U, V>& x);
    template <class T1, class T2, class U, class V>
      void construct(pair<T1, T2>* p, pair<U, V>&& x);

    template <class T>
      void destroy(T* p);

    scoped_allocator_adaptor select_on_container_copy_construction() const;
  };

  template<class OuterAlloc, class... InnerAllocs>
    scoped_allocator_adaptor(OuterAlloc, InnerAllocs...)
      -> scoped_allocator_adaptor<OuterAlloc, InnerAllocs...>;

  template <class OuterA1, class OuterA2, class... InnerAllocs>
    bool operator==(const scoped_allocator_adaptor<OuterA1, InnerAllocs...>& a,
                    const scoped_allocator_adaptor<OuterA2, InnerAllocs...>& b) noexcept;
  template <class OuterA1, class OuterA2, class... InnerAllocs>
    bool operator!=(const scoped_allocator_adaptor<OuterA1, InnerAllocs...>& a,
                    const scoped_allocator_adaptor<OuterA2, InnerAllocs...>& b) noexcept;
}

23.13.2 Scoped allocator adaptor member types [allocator.adaptor.types]

using inner_allocator_type = see below;

Type: scoped_­allocator_­adaptor<OuterAlloc> if sizeof...(InnerAllocs) is zero; otherwise,
scoped_­allocator_­adaptor<InnerAllocs...>.

using propagate_on_container_copy_assignment = see below;

Type: true_­type if allocator_­traits<A>​::​propagate_­on_­container_­copy_­assignment​::​value is true for any A in the set of OuterAlloc and InnerAllocs...; otherwise, false_­type.

using propagate_on_container_move_assignment = see below;

Type: true_­type if allocator_­traits<A>​::​propagate_­on_­container_­move_­assignment​::​value is true for any A in the set of OuterAlloc and InnerAllocs...; otherwise, false_­type.

using propagate_on_container_swap = see below;

Type: true_­type if allocator_­traits<A>​::​propagate_­on_­container_­swap​::​value is true for any A in the set of OuterAlloc and InnerAllocs...; otherwise, false_­type.

using is_always_equal = see below;

Type: true_­type if allocator_­traits<A>​::​is_­always_­equal​::​value is true for every A in the set of OuterAlloc and InnerAllocs...; otherwise, false_­type.

23.13.3 Scoped allocator adaptor constructors [allocator.adaptor.cnstr]

scoped_allocator_adaptor();

Effects: Value-initializes the OuterAlloc base class and the inner allocator object.

template <class OuterA2> scoped_allocator_adaptor(OuterA2&& outerAlloc, const InnerAllocs&... innerAllocs) noexcept;

Effects: Initializes the OuterAlloc base class with std​::​forward<OuterA2>(outerAlloc) and inner with innerAllocs... (hence recursively initializing each allocator within the adaptor with the corresponding allocator from the argument list).

Remarks: This constructor shall not participate in overload resolution unless is_­constructible_­v<OuterAlloc, OuterA2> is true.

scoped_allocator_adaptor(const scoped_allocator_adaptor& other) noexcept;

Effects: Initializes each allocator within the adaptor with the corresponding allocator from other.

scoped_allocator_adaptor(scoped_allocator_adaptor&& other) noexcept;

Effects: Move constructs each allocator within the adaptor with the corresponding allocator from other.

template <class OuterA2> scoped_allocator_adaptor(const scoped_allocator_adaptor<OuterA2, InnerAllocs...>& other) noexcept;

Effects: Initializes each allocator within the adaptor with the corresponding allocator from other.

Remarks: This constructor shall not participate in overload resolution unless is_­constructible_­v<OuterAlloc, const OuterA2&> is true.

template <class OuterA2> scoped_allocator_adaptor(scoped_allocator_adaptor<OuterA2, InnerAllocs...>&& other) noexcept;

Effects: Initializes each allocator within the adaptor with the corresponding allocator rvalue from other.

Remarks: This constructor shall not participate in overload resolution unless is_­constructible_­v<OuterAlloc, OuterA2> is true.

23.13.4 Scoped allocator adaptor members [allocator.adaptor.members]

In the construct member functions, OUTERMOST(x) is x if x does not have an outer_­allocator() member function and OUTERMOST(x.outer_­allocator()) otherwise; OUTERMOST_­ALLOC_­TRAITS(x) is allocator_­traits<decltype(OUTERMOST(x))>. [Note: OUTERMOST(x) and OUTERMOST_­ALLOC_­TRAITS(x) are recursive operations. It is incumbent upon the definition of outer_­allocator() to ensure that the recursion terminates. It will terminate for all instantiations of scoped_­allocator_­adaptor. end note]

inner_allocator_type& inner_allocator() noexcept; const inner_allocator_type& inner_allocator() const noexcept;

Returns: *this if sizeof...(InnerAllocs) is zero; otherwise, inner.

outer_allocator_type& outer_allocator() noexcept;

Returns: static_­cast<OuterAlloc&>(*this).

const outer_allocator_type& outer_allocator() const noexcept;

Returns: static_­cast<const OuterAlloc&>(*this).

pointer allocate(size_type n);

Returns: allocator_­traits<OuterAlloc>​::​allocate(outer_­allocator(), n).

pointer allocate(size_type n, const_void_pointer hint);

Returns: allocator_­traits<OuterAlloc>​::​allocate(outer_­allocator(), n, hint).

void deallocate(pointer p, size_type n) noexcept;

Effects: As if by: allocator_­traits<OuterAlloc>​::​deallocate(outer_­allocator(), p, n);

size_type max_size() const;

Returns: allocator_­traits<OuterAlloc>​::​max_­size(outer_­allocator()).

template <class T, class... Args> void construct(T* p, Args&&... args);

Effects:

  • If uses_­allocator_­v<T, inner_­allocator_­type> is false and is_­constructible_­v<T,
    Args...>
    is true, calls:

    OUTERMOST_ALLOC_TRAITS(*this)::construct(
        OUTERMOST(*this), p, std::forward<Args>(args)...)
  • Otherwise, if uses_­allocator_­v<T, inner_­allocator_­type> is true and is_­constructible_­v<T, allocator_­arg_­t, inner_­allocator_­type&, Args...> is true, calls:

    OUTERMOST_ALLOC_TRAITS(*this)::construct(
        OUTERMOST(*this), p, allocator_arg, inner_allocator(), std::forward<Args>(args)...)
  • Otherwise, if uses_­allocator_­v<T, inner_­allocator_­type> is true and is_­constructible_­v<T, Args..., inner_­allocator_­type&> is true, calls:

    OUTERMOST_ALLOC_TRAITS(*this)::construct(
        OUTERMOST(*this), p, std::forward<Args>(args)..., inner_allocator())
  • Otherwise, the program is ill-formed. [Note: An error will result if uses_­allocator evaluates to true but the specific constructor does not take an allocator. This definition prevents a silent failure to pass an inner allocator to a contained element. end note]

template <class T1, class T2, class... Args1, class... Args2> void construct(pair<T1, T2>* p, piecewise_construct_t, tuple<Args1...> x, tuple<Args2...> y);

Requires: all of the types in Args1 and Args2 shall be CopyConstructible.

Effects: Constructs a tuple object xprime from x by the following rules:

  • If uses_­allocator_­v<T1, inner_­allocator_­type> is false and is_­constructible_­v<T1,
    Args1...>
    is true, then xprime is x.

  • Otherwise, if uses_­allocator_­v<T1, inner_­allocator_­type> is true and is_­constructible_­v<T1, allocator_­arg_­t, inner_­allocator_­type&, Args1...> is true, then xprime is:

    tuple_cat(
        tuple<allocator_arg_t, inner_allocator_type&>(allocator_arg, inner_allocator()),
        std::move(x))
  • Otherwise, if uses_­allocator_­v<T1, inner_­allocator_­type> is true and is_­constructible_­v<T1, Args1..., inner_­allocator_­type&> is true, then xprime is:

    tuple_cat(std::move(x), tuple<inner_allocator_type&>(inner_allocator()))
  • Otherwise, the program is ill-formed.

and constructs a tuple object yprime from y by the following rules:

  • If uses_­allocator_­v<T2, inner_­allocator_­type> is false and is_­constructible_­v<T2,
    Args2...>
    is true, then yprime is y.

  • Otherwise, if uses_­allocator_­v<T2, inner_­allocator_­type> is true and is_­constructible_­v<T2, allocator_­arg_­t, inner_­allocator_­type&, Args2...> is true, then yprime is:

    tuple_cat(
        tuple<allocator_arg_t, inner_allocator_type&>(allocator_arg, inner_allocator()),
        std::move(y))
  • Otherwise, if uses_­allocator_­v<T2, inner_­allocator_­type> is true and is_­constructible_­v<T2, Args2..., inner_­allocator_­type&> is true, then yprime is:

    tuple_cat(std::move(y), tuple<inner_allocator_type&>(inner_allocator()))
  • Otherwise, the program is ill-formed.

then calls:

OUTERMOST_ALLOC_TRAITS(*this)::construct(
    OUTERMOST(*this), p, piecewise_construct, std::move(xprime), std::move(yprime))

template <class T1, class T2> void construct(pair<T1, T2>* p);

Effects: Equivalent to:

construct(p, piecewise_construct, tuple<>(), tuple<>());

template <class T1, class T2, class U, class V> void construct(pair<T1, T2>* p, U&& x, V&& y);

Effects: Equivalent to:

construct(p, piecewise_construct,
          forward_as_tuple(std::forward<U>(x)),
          forward_as_tuple(std::forward<V>(y)));

template <class T1, class T2, class U, class V> void construct(pair<T1, T2>* p, const pair<U, V>& x);

Effects: Equivalent to:

construct(p, piecewise_construct,
          forward_as_tuple(x.first),
          forward_as_tuple(x.second));

template <class T1, class T2, class U, class V> void construct(pair<T1, T2>* p, pair<U, V>&& x);

Effects: Equivalent to:

construct(p, piecewise_construct,
          forward_as_tuple(std::forward<U>(x.first)),
          forward_as_tuple(std::forward<V>(x.second)));

template <class T> void destroy(T* p);

Effects: Calls OUTERMOST_­ALLOC_­TRAITS(*this)​::​destroy(OUTERMOST(*this), p).

scoped_allocator_adaptor select_on_container_copy_construction() const;

Returns: A new scoped_­allocator_­adaptor object where each allocator A in the adaptor is initialized from the result of calling allocator_­traits<A>​::​select_­on_­container_­copy_­construction() on the corresponding allocator in *this.

23.13.5 Scoped allocator operators [scoped.adaptor.operators]

template <class OuterA1, class OuterA2, class... InnerAllocs> bool operator==(const scoped_allocator_adaptor<OuterA1, InnerAllocs...>& a, const scoped_allocator_adaptor<OuterA2, InnerAllocs...>& b) noexcept;

Returns: If sizeof...(InnerAllocs) is zero,

a.outer_allocator() == b.outer_allocator()

otherwise

a.outer_allocator() == b.outer_allocator() && a.inner_allocator() == b.inner_allocator()

template <class OuterA1, class OuterA2, class... InnerAllocs> bool operator!=(const scoped_allocator_adaptor<OuterA1, InnerAllocs...>& a, const scoped_allocator_adaptor<OuterA2, InnerAllocs...>& b) noexcept;

Returns: !(a == b).