Reputation: 3763
Consider the following:
#include <set>
#include <map>
struct MyClass
{
MyClass(int i);
MyClass(MyClass const&) = delete;
~MyClass();
bool operator<(const MyClass& r) const { return v < r.v; }
int v;
};
void map_set_move_test()
{
std::set<MyClass> s1, s2;
std::map<int, MyClass> m1;
s1.emplace(123);
s2.insert(std::move(s1.extract(s1.begin())));
// This fails
m1.insert(std::move(std::make_pair(1, std::move(s2.extract(s2.begin()).value()))));
}
I used std::set::extract
to successfully move an element from std::set
to another std::set
, as in:
s2.insert(std::move(s1.extract(s1.begin())));
But the compiler doesn't allow moving the element to std::map
this way:
m1.insert(std::move(std::make_pair(1, std::move(s2.extract(s2.begin()).value()))));
Any help would be appreciated. Link to compiler explorer.
Upvotes: 3
Views: 249
Reputation: 131546
This is a problematic example, because MyClass is not merely non-copyable, but implicitly non-movable - which is probably not what you meant. (I think MyClass becomes immovable as a result of you explicitly deleting the copy constructor; see this answer.)
If you do make MyClass
movable, like so:
class MyClass : NonCopyable
{
public:
MyClass(int i) : v(i) {
std::cout << "constructor" << std::endl;
}
MyClass(MyClass&& other) : v(other.v) {
std::cout << "move constructor" << std::endl;
}
~MyClass() {
std::cout << "destructor" << std::endl;
}
bool operator<(const MyClass& r) const {
return v < r.v;
}
int v;
};
all seems to go well, when you write, say.
m1.emplace(
1,
std::move(
s2.extract(s2.begin()).value()
)
);
You can see this working on GodBolt.
PS - As @DavisHerring suggests, you might want to use the try_emplace()
method instead, if you don't want to overwrite an existing value.
Upvotes: 4
Reputation: 39818
The point of extract
and the corresponding overload of insert
is to manipulate node-based containers without memory allocation. (One interesting such manipulation is to change std::map
keys.) That cannot work here because the nodes are different types (viz., one has a key and the other doesn’t), so you need to just use the value with a regular insert
(or the more ergonomic try_emplace
).
Upvotes: 3