将unique_ptr从一个集合移动到另一个集合

Move unique_ptr from set to set

本文关键字:集合 一个 移动 另一个 unique ptr      更新时间:2023-10-16

我似乎无法理解这一点,并尝试了中的建议

在集合之间移动`unique_ptr`

如何移动std::unique_ptr<gt;从一个STL容器到另一个?

我有两个包含唯一指针的集合:

std::set<std::unique_ptr<some_type>> s1, s2;

指针当然是唯一的,但some_type的值可能是也可能不是,因此在将s2加入s1之后,s1的大小可能与|s1+s2|相同或大。

看来我应该能够做到这一点:

move(s2.begin(), s2.end(), inserter(s1, s1.end()));

但这失败了,clang++3.8/g++5.4。

这里少了什么?

它不起作用,因为std::set只允许const访问其元素。没有办法将某些东西从std::set中移出。请参阅是否可以将项目从std::集中移出?

在C++14中没有很好的方法可以做到这一点,但在C++17中,有一种merge方法可用于此目的,它只需重新排列数据结构的内部指针,而不复制或移动任何元素:

s1.merge(s2);

C++14中一个比较合理的变通方法是将std::set<std::unique_ptr<T>>更改为std::map<T*, std::unique_ptr<T>>。然后你可以做:

while (!s1.empty()) {
    s2[s1.begin()->first] = std::move(s1.begin()->second);
    s1.erase(s1.begin());
}

当前您正在将集合成员资格与所有权混为一谈,这就是问题的根源。

解决方案:使用一组原始指针,并将所有权转移到其他地方。


关于设想的

move(s2.begin(), s2.end(), inserter(s1, s1.end()));

在标准库中,move只是一个荣耀的演员阵容,而不是一个动作例程。命令式名称形式具有误导性。把std::move想象成as_moveable

在C++17中,您可以使用std::set::merge来执行您想要的操作,如下例所示:

std::set<std::unique_ptr<T>> s1, s2;
...
s1.merge(s2);

实时演示

C++11的变通方法虽然相当昂贵,但有点违背了unique_ptr的概念,这也需要您的对象是可复制的。将第二个std::set的对象复制到新的std::unique_ptr中,您将插入到第一个集合中:

std::set<std::unique_ptr<T>> s1, s2;
...
for(auto &&e : s2) {
  s1.insert(std::make_unique<T>(*e));
}
s2.clear();

请注意,在最后,你必须clear你的第二套,才能从std::unique_ptr概念的疯狂分离所引起的混乱中恢复过来。

实时演示