0

Consider this example:

std::map<int, int> example;
example.insert({ 0, 1 });
example.insert({ 1, 2 });
auto newMap = std::move(example);
example.insert({ 3, 1 }); // I would expect a crash here, yet it still functions OK

In Bjarne Stroustrup's document (link), he explains how std::move and move-semantics behave.

This move() gives its target the value of its argument, but is not obliged to preserve the value of its source. So, for a vector, move() could reasonably be expected to leave its argument as a zero-capacity vector to avoid having to copy all the elements. In other words, move is a potentially destructive read.

I would expect my "example" map to have no valid internal state after the move. Yet I can still insert to it without any problem, why? Is this behavior dependable or is it compiler/platform specific?

For easy copy-paste, here is the code I used (C++14, -O3):

#include <map>
#include <iostream>

int main() {
    std::map<int, int> example;
    example.insert({ 0, 1 });
    example.insert({ 1, 2 });
    std::cout << "example\n";
    for(auto& pair : example) {
        std::cout << pair.first << " " << pair.second << "\n";   
    }
    std::cout << "\nafter move\n";
    auto newMap = std::move(example);
    std::cout << "newMap\n";
    for(auto& pair : newMap) {
        std::cout << pair.first << " " << pair.second << "\n";   
    }
    std::cout << "example (empty)\n";
    for(auto& pair : example) {
        std::cout << pair.first << " " << pair.second << "\n";   
    }
    
    std::cout << "\ninserting to example\n";
    example.insert({ 3, 1 });
    example.insert({ 4, 2 });
    std::cout << "example\n";
    for(auto& pair : example) {
        std::cout << pair.first << " " << pair.second << "\n";   
    }
    std::cout << "why can I still insert to example?\n";
}
Doga Oruc
  • 783
  • 3
  • 16
  • 2
    `std::move` leaves its argument in a *valid*, but *undefined* state. – Tom Gebel Feb 07 '21 at 02:33
  • Please define the terms "valid" and "undefined". – Doga Oruc Feb 07 '21 at 02:33
  • @DogaOruc: ... those words have common English definitions, and their use here is fairly obvious. – Nicol Bolas Feb 07 '21 at 02:36
  • "valid": its invariants are still maintained. "undefined": not defined (it can be in any of the valid states that exist). – spectras Feb 07 '21 at 02:36
  • 2
    *"map to be a zero-capacity container"* -- capacity is an attribute of vectors, not of maps. – JaMiT Feb 07 '21 at 02:41
  • @spectras what do you mean by invariants? what "invariants" a map have that has to be maintained? – Doga Oruc Feb 07 '21 at 02:46
  • I guess the safest way to go about my way with "example" is calling ```clear()``` on it. – Doga Oruc Feb 07 '21 at 02:48
  • 2
    For most standard C++ library objects, after being moved from, they are left in a valid-but-unspecified state. Suitable for begin assigned to, or to be destructed. Some objects, like std::vector or std::unique_ptr, have additional guarantees. All member functions that have no preconditions may also be called. Your own objects will be in whatever state you program them to be in after being moved from. – Eljay Feb 07 '21 at 03:00
  • You can write a function (eg. `template auto clear_move(T& m) {/* ...*/ }` ) that creates a default constructed temporary and `std:::swap`s with it to leave the *moved from* object in a well-defined state. – Galik Feb 07 '21 at 03:03
  • 2
    For a std::lib object in a valid but unspecified state, you can call any function on that object that has no precondition. You can't call a function with a precondition because you don't know if the object's state meets that precondition. But an object in a valid state can undergo any algorithm/function which has no preconditions. Typically, operations such as assignment and destruction have no preconditions. Check the type's documentation for other operations which have no preconditions. – Howard Hinnant Feb 07 '21 at 03:38
  • Very simply said: _valid_ means that you can use the object; _unspecified state_ means that you cannot make any assumptions about its content. – Daniel Langr Feb 07 '21 at 04:08

0 Answers0