如何使用extract将不可复制的元素从std::set移动到std::map



考虑以下内容:

#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()))));
}

我使用std::set::extract成功地将一个元素从std::set移动到另一个std::set,如:

s2.insert(std::move(s1.extract(s1.begin())));

但是编译器不允许以这种方式将元素移动到std::map

m1.insert(std::move(std::make_pair(1, std::move(s2.extract(s2.begin()).value()))));

如有任何帮助,我们将不胜感激。指向编译器资源管理器的链接。

这是一个有问题的例子,因为MyClass不仅不可复制,而且隐含地不可移动——这可能不是你的意思。(我认为MyClass由于您显式删除了复制构造函数而变得不可移动;请参阅此答案。(

如果你确实让MyClass可以移动,就像这样:

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;
};

一切似乎都很顺利,当你写的时候,说。

m1.emplace(
1,
std::move( 
s2.extract(s2.begin()).value() 
)
);

您可以在GodBolt上看到这一点。


PS-正如@DavisHerring所建议的,如果您不想覆盖现有值,您可能需要使用try_emplace()方法

extract和相应的insert重载的目的是在没有内存分配的情况下操作基于节点的容器。(一个有趣的操作是更改std::map键。(这在这里不起作用,因为节点是不同的类型(,一个有键,另一个没有(,所以您只需要将该值与常规insert(或更符合人体工程学的try_emplace(一起使用。

最新更新