This page is a snapshot from the LWG issues list, see the Library Active Issues List for more information and the meaning of Resolved status.

### 1321. `scoped_allocator_adaptor construct` and `destroy` don't use `allocator_traits`

Section: 20.5.4 [allocator.adaptor.members] Status: Resolved Submitter: Howard Hinnant Opened: 2010-02-16 Last modified: 2016-01-28

Priority: Not Prioritized

View all other issues in [allocator.adaptor.members].

View all issues with Resolved status.

Discussion:

20.5.4 [allocator.adaptor.members] p8-9 says:

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

> > 8 Effects: let `OUTERMOST(x)` be `x` if `x` does not have an `outer_allocator()` function and `OUTERMOST(x.outer_allocator())` otherwise.

> > - If `uses_allocator<T, inner_allocator_type>::value` is `false` and `is_constructible<T, Args...>::value` is `true`, calls `OUTERMOST(*this).construct(p, std::forward<Args>(args)...)`.
> > - Otherwise, if `uses_allocator<T, inner_allocator_type>::value` is `true` and `is_constructible<T, allocator_arg_t, inner_allocator_type, Args...>::value` is `true`, calls `OUTERMOST(*this).construct(p, allocator_arg, inner_allocator(),std::forward<Args>(args)...)`.
> > - Otherwise, if `uses_allocator<T, inner_allocator_type>::value` is `true` and `is_constructible<T, Args..., inner_allocator_type>::value` is `true`, calls `OUTERMOST(*this).construct(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 T>
>       void destroy(T* p);

> > 9 Effects: calls `outer_allocator().destroy(p)`.

In all other calls where applicable `scoped_allocator_adaptor` does not call members of an allocator directly, but rather does so indirectly via `allocator_traits`. For example:

>     size_type max_size() const;

> > 7 Returns: `allocator_traits<OuterAlloc>::max_size(outer_allocator())`.

Indeed, without the indirection through `allocator_traits` the definitions for `construct` and `destroy` are likely to fail at compile time since the `outer_allocator()` may not have the members `construct` and `destroy`.

[ The proposed wording is a product of Pablo, Daniel and Howard. ]

[ 2010 Pittsburgh: Moved to NAD Editorial. Rationale added below. ]

Rationale:

Solved by N3059.

Proposed resolution:

In 20.5.4 [allocator.adaptor.members] move and change p8 as indicated, and change p9 as indicated:

> Let `OUTERMOST(x)` be `x` if `x` does not have an `outer_allocator()` member function and `OUTERMOST(x.outer_allocator())` otherwise. Let `OUTERMOST_ALLOC_TRAITS(x)` be `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]

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

> > 8 Effects: let `OUTERMOST(x)` be `x` if `x` does not have an `outer_allocator()` function and `OUTERMOST(x.outer_allocator())` otherwise.

> > - If `uses_allocator<T, inner_allocator_type>::value` is `false` and `is_constructible<T, Args...>::value` is `true`, calls `OUTERMOST(*this). OUTERMOST_ALLOC_TRAITS(outer_allocator())::construct( OUTERMOST(outer_allocator()), p, std::forward<Args>(args)... )`.
> > - Otherwise, if `uses_allocator<T, inner_allocator_type>::value` is `true` and `is_constructible<T, allocator_arg_t, inner_allocator_type, Args...>::value` is `true`, calls `OUTERMOST(*this). OUTERMOST_ALLOC_TRAITS(outer_allocator())::construct( OUTERMOST(outer_allocator()), p, allocator_arg, inner_allocator(), std::forward<Args>(args)... )`.
> > - Otherwise, if `uses_allocator<T, inner_allocator_type>::value` is `true` and `is_constructible<T, Args..., inner_allocator_type>::value` is `true`, calls `OUTERMOST(*this). OUTERMOST_ALLOC_TRAITS(outer_allocator())::construct( OUTERMOST(outer_allocator()), 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 T>
>       void destroy(T* p);

> > 9 Effects: calls `outer_allocator(). OUTERMOST_ALLOC_TRAITS(outer_allocator())::destroy( OUTERMOST(outer_allocator()), p)`.