如何使用提取将不可复制的元素从 std::set 移动到 std::map?
How to move a non-copyable element from std::set to std::map using extract?
考虑以下因素:
#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()))));
如有任何帮助,我们将不胜感激。 Link to compiler explorer.
extract
的要点和insert
的相应重载是在没有内存分配的情况下操作node-based个容器。 (一个有趣的操作是更改 std::map
键。)这在这里不起作用,因为节点是不同类型的(viz.,一个有键,另一个没有),因此您只需使用具有 常规 insert
(或更符合人体工程学的 try_emplace
)的值。
这是一个有问题的示例,因为 MyClass 不仅是 non-copyable,而且隐含地 non-movable - 这可能不是您的意思。 (我认为 MyClass 由于您显式删除复制构造函数而变得不可移动;参见 this answer。)
如果你让 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()
方法。
考虑以下因素:
#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()))));
如有任何帮助,我们将不胜感激。 Link to compiler explorer.
extract
的要点和insert
的相应重载是在没有内存分配的情况下操作node-based个容器。 (一个有趣的操作是更改 std::map
键。)这在这里不起作用,因为节点是不同类型的(viz.,一个有键,另一个没有),因此您只需使用具有 常规 insert
(或更符合人体工程学的 try_emplace
)的值。
这是一个有问题的示例,因为 MyClass 不仅是 non-copyable,而且隐含地 non-movable - 这可能不是您的意思。 (我认为 MyClass 由于您显式删除复制构造函数而变得不可移动;参见 this answer。)
如果你让 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()
方法。