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.
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)
bex
ifx
does not have anouter_allocator()
function andOUTERMOST(x.outer_allocator())
otherwise.
- If
uses_allocator<T, inner_allocator_type>::value
isfalse
andis_constructible<T, Args...>::value
istrue
, callsOUTERMOST(*this).construct(p, std::forward<Args>(args)...)
.- Otherwise, if
uses_allocator<T, inner_allocator_type>::value
istrue
andis_constructible<T, allocator_arg_t, inner_allocator_type, Args...>::value
istrue
, callsOUTERMOST(*this).construct(p, allocator_arg, inner_allocator(),std::forward<Args>(args)...)
.- Otherwise, if
uses_allocator<T, inner_allocator_type>::value
istrue
andis_constructible<T, Args..., inner_allocator_type>::value
istrue
, callsOUTERMOST(*this).construct(p, std::forward<Args>(args)..., inner_allocator())
.- Otherwise, the program is ill-formed. [Note: an error will result if
uses_allocator
evaluates totrue
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)
bex
ifx
does not have anouter_allocator()
member function andOUTERMOST(x.outer_allocator())
otherwise. LetOUTERMOST_ALLOC_TRAITS(x)
beallocator_traits<decltype(OUTERMOST(x))>
. [Note:OUTERMOST(x)
andOUTERMOST_ALLOC_TRAITS(x)
are recursive operations. It is incumbent upon the definition ofouter_allocator()
to ensure that the recursion terminates. It will terminate for all instantiations ofscoped_allocator_adaptor
. — end note]template <class T, class... Args> void construct(T* p, Args&&... args);8 Effects:
letOUTERMOST(x)
bex
ifx
does not have anouter_allocator()
function andOUTERMOST(x.outer_allocator())
otherwise.
- If
uses_allocator<T, inner_allocator_type>::value
isfalse
andis_constructible<T, Args...>::value
istrue
, 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
istrue
andis_constructible<T, allocator_arg_t, inner_allocator_type, Args...>::value
istrue
, 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
istrue
andis_constructible<T, Args..., inner_allocator_type>::value
istrue
, 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 totrue
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)