Allocators
must be no-throw swappableSection: 16.4.4.6 [allocator.requirements] Status: C++17 Submitter: Daniel Krügler Opened: 2010-11-17 Last modified: 2017-07-30
Priority: 2
View other active issues in [allocator.requirements].
View all other issues in [allocator.requirements].
View all issues with C++17 status.
Discussion:
During the Batavia meeting it turned out that there is a definition
hole for types satisfying the Allocators
requirements: The problem
became obvious when it was discussed whether all swap
functions
of Containers
with internal data handles can be safely tagged
with noexcept
or not. While it is correct that the implicit
swap
function of an allocator is required to be a no-throw
operation (because move/copy-constructors and assignment operators are
required to be no-throw functions), there are no such requirements
for specialized swap
overloads for a particular allocator.
Containers
are
required to support swappable Allocators
, when the value
allocator_traits<>::propagate_on_container_swap
evaluates
to true
.
[2011-02-10 Alberto, Daniel, and Pablo collaborated on the proposed wording]
The proposed resolution (based on N3225) attempts to solve the following problems:
X::propagate_on_container_copy_assignment
, X::propagate_on_container_move_assignment
, and
X::propagate_on_container_swap
only describe operations, but no requirements. In fact, if and only
if these compile-time predicates evaluate to true
, the additional requirements
CopyAssignable
, no-throw MoveAssignable
, and no-throw lvalue Swappable
,
respectively, are imposed on the allocator types.a.get_allocator() == b.get_allocator()
or allocator_traits<allocator_type>::propagate_on_container_swap::value == true
), which should be cleaned up.[2011-04-08 Pablo comments]
I'm implementing a version of list now and I actually do find it impossible to write an exception-safe assignment operator unless I can assume that allocator assignment does not throw. (The problem is that I use a sentinel node and I need to allocate a new sentinel using the new allocator without destroying the old one -- then swap the allocator and sentinel pointer in atomically, without risk of an exception leaving one inconsistent with the other.
Please update the proposed resolution to add the nothrow requirement to copy-assignment.[2014-02-14 Issaquah: Move to Ready]
Fix a couple of grammar issues related to calling swap
and move to Ready.
Proposed resolution:
Adapt the following three rows from Table 44 — Allocator requirements:
Table 44 — Allocator requirements Expression Return type Assertion/note
pre-/post-conditionDefault X::propagate_on_container_copy_assignment
Identical to or derived from true_type
orfalse_type
true_type
only if an allocator of typeX
should be copied
when the client container is copy-assigned. See Note B, below.false_type
X::propagate_on_container_move_assignment
Identical to or derived from true_type
orfalse_type
true_type
only if an allocator of typeX
should be moved
when the client container is move-assigned. See Note B, below.false_type
X::propagate_on_container_swap
Identical to or derived from true_type
orfalse_type
true_type
only if an allocator of typeX
should be swapped
when the client container is swapped. See Note B, below.false_type
Following 16.4.4.6 [allocator.requirements] p. 3 insert a new normative paragraph:
Note B: If
X::propagate_on_container_copy_assignment::value
is true,X
shall satisfy theCopyAssignable
requirements (Table 39 [copyassignable]) and the copy operation shall not throw exceptions. IfX::propagate_on_container_move_assignment::value
is true,X
shall satisfy theMoveAssignable
requirements (Table 38 [moveassignable]) and the move operation shall not throw exceptions. IfX::propagate_on_container_swap::value
is true, lvalues ofX
shall be swappable (16.4.4.3 [swappable.requirements]) and theswap
operation shall not throw exceptions.
Modify 23.2.2 [container.requirements.general] p. 8 and p. 9 as indicated:
8 - [..] The allocator may be replaced only via assignment or
9 - The expressionswap()
. Allocator replacement is performed by copy assignment, move assignment, or swapping of the allocator only ifallocator_traits<allocator_type>::propagate_on_container_copy_assignment::value
,allocator_traits<allocator_type>::propagate_on_container_move_assignment::value
, orallocator_traits<allocator_type>::propagate_on_container_swap::value
is true within the implementation of the corresponding container operation.The behavior of a call to a container's. In all container types defined in this Clause, the memberswap
function is undefined unless the objects being swapped have allocators that compare equal orallocator_traits<allocator_type>::propagate_on_container_swap::value
is trueget_allocator()
returns a copy of the allocator used to construct the container or, if that allocator has been replaced, a copy of the most recent replacement.a.swap(b)
, for containersa
andb
of a standard container type other thanarray
, shall exchange the values ofa
andb
without invoking any move, copy, or swap operations on the individual container elements. Lvalues of aAnyCompare
,Pred
, orHash
objectstypes belonging toa
andb
shall be swappable and shall be exchanged byunqualified calls to non-membercallingswap
as described in 16.4.4.3 [swappable.requirements]. Ifallocator_traits<allocator_type>::propagate_on_container_swap::value
istrue
, then lvalues ofallocator_type
shall be swappable and the allocators ofa
andb
shall also be exchangedusing an unqualified call to non-memberby callingswap
as described in 16.4.4.3 [swappable.requirements]. Otherwise,theythe allocators shall not be swapped, and the behavior is undefined unlessa.get_allocator() == b.get_allocator()
. Every iterator referring to an element in one container before the swap shall refer to the same element in the other container after the swap. It is unspecified whether an iterator with valuea.end()
before the swap will have valueb.end()
after the swap.