What does the standard library guarantee about self move assignment?

C++StlC++11Move Semantics

C++ Problem Overview


What does the C++11 standard say about self move assignment in relation to the standard library? To be more concrete, what, if anything, is guaranteed about what selfAssign does?

template<class T>
std::vector<T> selfAssign(std::vector<T> v) {
  v = std::move(v);
  return v;
}

C++ Solutions


Solution 1 - C++

17.6.4.9 Function arguments [res.on.arguments]

> 1 Each of the following applies to all arguments to functions defined > in the C++ standard library, unless explicitly stated otherwise. > > ... > > * 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 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 anlvalue. —endnote]

So, the implementation of std::vector<T, A>::operator=(vector&& other) is allowed to assume that other is a prvalue. And if other is a prvalue, self-move-assignment is not possible.

What is likely to happen:

v will be left in a resource-less state (0 capacity). If v already has 0 capacity, then this will be a no-op.

Update

The latest working draft, N4618 has been modified to clearly state that in the MoveAssignable requirements the expression:

t = rv

(where rv is an rvalue), t need only be the equivalent value of rv prior to the assignment if t and rv do not reference the same object. And regardless, rv's state is unspecified after the assignment. There is an additional note for further clarification:

> rv must still meet the requirements of the library component that is using it, whether or not t and rv refer to the same object.

Solution 2 - C++

There is a relevant post by Eric Niebler with multiple links, e.g. to this answer by Howard Hinnant.

The latest С++20 working draft (N4861) is still kind of ambiguous on the matter for my taste. However, there is a recent Library Working Group issue 2839 which adds the following explicit statement at [lib.types.movedfrom]/2:

> 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.

It was already in the N4885 working draft of C++23.

So, selfAssign is guaranteed to not cause undefined behavior and, as there are no extra guarantees for std::vector, leave v in some valid state.

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
QuestionBjarke H. RouneView Question on Stackoverflow
Solution 1 - C++Howard HinnantView Answer on Stackoverflow
Solution 2 - C++yeputonsView Answer on Stackoverflow