This code confuses me:
struct foo {
int i;
foo(int j) : i(j) {}
foo(const foo &) = delete;
foo(foo &&) = delete;
foo &operator=(const foo&) = delete;
foo &operator=(foo&&) = delete;
};
bool operator<(const foo &f1, const foo &f2)
{
return f1.i < f2.i;
}
int main(int argc, char **argv)
{
std::map<foo,int> f;
std::map<foo,int> f2 = f; //error (as expected)
std::map<foo,int> f3 = std::move(f); //no error (why?)
return 0;
}
Because I get no error there, it seems like when moving a map no key object is created (not even for moving another key object into it).
Why not? Can I rely on this behavior according to the C++11 standard?
More generally, what copying/moving requirements does a std::map
place on the key and value types and under what conditions?
Starting with C++17, we can use the std::map::merge member function to copy content from a map to another map. This is the recommended way to copy the contents of a map to an existing map in C++17 and above. That's all about copying entries of a map to another map in C++.
To update an existing value in the map, first we will find the value with the given key using map::find() function. If the key exists, then will update it with new value.
Yes -- when you insert an item into an std::map, you pass it by value, so what it contains is a copy of what you passed.
Copy-assignment of one map to another requires copying each item. Since you cannot copy items, you cannot copy-assign the maps.
Whether the actual map object is empty at runtime is immaterial, since these are purely static considerations, determined entirely by the types of the objects.
(It's like asking why sin(0)
requires a floating point unit when clearly the result is an integer.)
Moving the entire map, on the other hand, is fine because the container is node-based and no actual values are mutated, just the nodes are. In fact, move-constructing or move-assigning node based containers doesn't require the elements to be copyable or movable or assignable at all.
(This should be true for all containers that manage dynamic memory in a suitable fashion, such as via std::allocator<value_type>
, but it would of course not be true for something like std::array
, and it would be interesting whether or not it would hold for std::dynarray
, and as @Jonathan Wakely noted, if the allocation scheme isn't able to move nodes wholesale.)
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With