Search code examples
c++language-lawyermove-semantics

Is it guaranteed that a container will destruct existing objects during std::move?


Consider the following example:

#include <iostream>
#include <vector>

class A {
public:
    A(const A&) = default;
    A(A&&) = default;
    A& operator=(const A&) = default;
    A& operator=(A&&) = default;

    A() = default;
    ~A() {
        std::cout << "~A()\n";
    }
};

int main() {
    std::vector<A> v1;
    std::vector<A> v2;

    v1.emplace_back();
    v1 = std::move(v2);
    std::cout << "moved\n";
}

The output is:

~A()
moved

My question is: Can I rely on std::move to destruct elements inside v1? Or, in other words, is the output above guaranteed, or can I get:

moved
~A()

It would be surprising if the latter is possible, but I didn't find a definite answer, and didn't find anything explicit in the standard. That could happen if the move assignment operator is implemented with std::swap or similar, but I didn't find a solid answer regarding whether that's valid or not.


Solution

  • While swapping would be a valid implementation for move assignment in general, standard library containers have extra requirements. Table 73:

    Expression: a = rv
    Return type: X&
    Operational semantics: All existing elements of a are either move assigned to or destroyed
    Assertion/Note pre-/post-condition: Postconditions: a is equal to the value that rv had before this assignment
    Complexity: linear

    So a swap wouldn't suffice, since that wouldn't move-assign to or destroy the original v1[0]