This page is a snapshot from the LWG issues list, see the Library Active Issues List for more information and the meaning of WP status.
Section: 16.4.6.15 [lib.types.movedfrom], 16.4.5.9 [res.on.arguments], 24.2.2.1 [container.requirements.general] Status: WP Submitter: Tim Song Opened: 2016-12-09 Last modified: 2020-11-09
Priority: 2
View all issues with WP status.
Discussion:
LWG 2468's resolution added to MoveAssignable the requirement to tolerate self-move-assignment, but that does nothing for library types that aren't explicitly specified to meet MoveAssignable other than make those types not meet MoveAssignable any longer.
To realize the intent here, we need to carve out an exception to 16.4.5.9 [res.on.arguments]'s restriction for move assignment operators and specify that self-move-assignment results in valid but unspecified state unless otherwise specified. The proposed wording below adds that to 16.4.6.15 [lib.types.movedfrom] since it seems to fit well with the theme of the current paragraph in that section. In addition, to address the issue with 24.2.2.1 [container.requirements.general] noted in LWG 2468's discussion, the requirement tables in that subclause will need to be edited in a way similar to LWG 2468.[2017-01-27 Telecon]
Priority 2
[2018-1-26 issues processing telecon]
Status to 'Open'; Howard to reword using 'MoveAssignable'.
Previous resolution [SUPERSEDED]:
This wording is relative to N4618.
Add a new paragraph at the end of 16.4.6.15 [lib.types.movedfrom]:
-1- Objects of types defined in the C++ standard library may be moved from (12.8). Move operations may be explicitly specified or implicitly generated. Unless otherwise specified, such moved-from objects shall be placed in a valid but unspecified state.
-?- An object of a type defined in the C++ standard library may be move-assigned (11.4.6 [class.copy.assign]) to itself. Such an assignment places the object in a valid but unspecified state unless otherwise specified.Add a note at the end of 16.4.5.9 [res.on.arguments]/1, bullet 3, as indicated:
-1- Each of the following applies to all arguments to functions defined in the C++ standard library, unless explicitly stated otherwise.
(1.1) — […]
(1.2) — […]
(1.3) — If a function argument binds to an rvalue reference parameter, the implementation may assume that this parameter is a unique reference to this argument. [Note: If the parameter is a generic parameter of the form T&& and an lvalue of type A is bound, the argument binds to an lvalue reference (14.8.2.1) and thus is not covered by the previous sentence. — end note] [Note: If a program casts an lvalue to an xvalue while passing that lvalue to a library function (e.g. by calling the function with the argument std::move(x)), the program is effectively asking that function to treat that lvalue as a temporary. The implementation is free to optimize away aliasing checks which might be needed if the argument was an lvalue. — end note] [Note: This does not apply to the argument passed to a move assignment operator (16.4.6.15 [lib.types.movedfrom]). — end note]
Edit Table 83 "Container requirements" in 24.2.2.1 [container.requirements.general] as indicated:
Table 83 — Container requirements Expression Return type Operational
semanticsAssertion/note
pre-/post-conditionComplexity … a = rv T& All existing elements of a
are either move
assigned to or
destroyedpost: If a and rv do not refer to the same object,
a shall be equal to the value that
rv had before this assignmentlinear … Edit Table 86 "Allocator-aware container requirements" in 24.2.2.1 [container.requirements.general] as indicated:
Table 86 — Allocator-aware container requirements Expression Return type Assertion/note
pre-/post-conditionComplexity … a = rv T& Requires: If allocator_traits<allocator_type
>::propagate_on_container_move_assignment::value
is false, T is MoveInsertable
into X and MoveAssignable.
All existing elements of a are either
move assigned to or destroyed.
post: If a and rv do not refer
to the same object, a shall be equal
to the value that rv had before this assignmentlinear …
[2018-08-16, Howard comments and provides updated wording]
I agreed to provide proposed wording for LWG 2839 that was reworded to use MoveAssignable. The advantage of this is that MoveAssignable specifies the self-assignment case, thus we do not need to repeat ourselves.
[2018-08-23 Batavia Issues processing]
Howard and Tim to discuss a revised P/R.
Previous resolution [SUPERSEDED]:
This wording is relative to N4762.
Add a new subsection to 16.4.6 [conforming] after 16.4.6.5 [member.functions]:
Special members [conforming.special]
Class types defined by the C++ standard library and specified to be default constructible, move constructible, copy constructible, move assignable, copy assignable, or destructible, shall meet the associated requirements Cpp17DefaultConstructible, Cpp17MoveConstructible, Cpp17CopyConstructible, Cpp17MoveAssignable, Cpp17CopyAssignable, and Cpp17Destructible, respectively (16.4.4.2 [utility.arg.requirements]).
[2020-06-06 Tim restores and updates P/R following 2020-05-29 telecon discussion]
The standard doesn't define phrases like "default constructible" used in the previous P/R. Moreover, the library provides a variety of wrapper types, and whether these types meet the semantic requirements of Cpp17Meowable (and maybe even syntactic, depending on how "copy constructible" is interpreted) depends on the property of their underlying wrapped types, which might not even be an object type (e.g., tuple or pair of references). This is a large can of worms (see LWG 2146) that we don't want to get into.
There is a suggestion in the telecon to blanket-exempt move-assignment operators from the 16.4.5.9 [res.on.arguments] 1.3 requirement. The revised wording below does not do so, as that would carve out not just self-move-assignment but also other aliasing scenarios in which the target object owns the source object. Whether such scenarios should be permitted is outside the scope of this issue, though notably assignable_from (18.4.8 [concept.assignable]) contains a note alluding to these cases and suggesting that they should be considered to be outside the domain of = entirely.[2020-07-17; issue processing telecon]
LWG reviewed the latest proposed resolution. Unanimous consent to move to Ready.
[2020-11-09 Approved In November virtual meeting. Status changed: Ready → WP.]
Proposed resolution:
This wording is relative to N4861.
Add a new paragraph at the end of 16.4.6.15 [lib.types.movedfrom]:
-1- Objects of types defined in the C++ standard library may be moved from ( [clss.copy.ctor]). Move operations may be explicitly specified or implicitly generated. Unless otherwise specified, such moved-from objects shall be placed in a valid but unspecified state.
-?- An object of a type defined in the C++ standard library may be move-assigned (11.4.6 [class.copy.assign]) to itself. Unless otherwise specified, such an assignment places the object in a valid but unspecified state.
Edit 16.4.5.9 [res.on.arguments]/1, bullet 3, as indicated:
-1- Each of the following applies to all arguments to functions defined in the C++ standard library, unless explicitly stated otherwise.
(1.1) — […]
(1.2) — […]
(1.3) — If a function argument binds to an rvalue reference parameter, the implementation may assume that this parameter is a unique reference to this argument, except that the argument passed to a move-assignment operator may be a reference to *this (16.4.6.15 [lib.types.movedfrom]). [Note: If the type of a parameter is a
generic parameter of the form T&& and an lvalue of type A is bound, the argument binds to an lvalue reference (13.10.3.2 [temp.deduct.call]) and thus is not covered by the previous sentence.forwarding reference (13.10.3.2 [temp.deduct.call]) that is deduced to an lvalue reference type, then the argument is not bound to an rvalue reference. — end note] [Note: If a program casts an lvalue to an xvalue while passing that lvalue to a library function (e.g. by calling the function with the argument std::move(x)), the program is effectively asking that function to treat that lvalue as a temporary. The implementation is free to optimize away aliasing checks which might be needed if the argument was an lvalue. — end note]
Edit Table 73 "Container requirements" in 24.2.2.1 [container.requirements.general] as indicated:
Table 73 — Container requirements Expression Return type Operational
semanticsAssertion/note
pre-/post-conditionComplexity … a = rv T& All existing elements of a are either move assigned to or destroyed Postconditions: If a and rv do not refer to the same object, a is equal to the value that rv had before this assignment. linear …
Edit Table 76 "Allocator-aware container requirements" in 24.2.2.1 [container.requirements.general] as indicated:
Table 86 — Allocator-aware container requirements Expression Return type Assertion/note
pre-/post-conditionComplexity … a = rv T& Preconditions: If allocator_traits<allocator_type>
::propagate_on_container_move_assignment::value is false,
T is Cpp17MoveInsertable into X and Cpp17MoveAssignable.
Effects: All existing elements of a are either move assigned to or destroyed.
Postconditions: If a and rv do not refer to the same object, a is equal to the value that rv had before this assignment.linear …