从std :: set中提取move only类型

时间:2017-07-11 09:44:35

标签: c++ c++11 stl set move

我有std::set<std::unique_ptr<T>>,我想将其移至std::vector<std::unique_ptr<T>>

#include <set>
#include <vector>
#include <memory>

class C {};

int main()
{
  std::set<std::unique_ptr<const C>> s;
  std::vector<std::unique_ptr<const C>> v;
  std::move(s.begin(), s.end(), std::back_inserter(v));
}

这在VS2017上出现以下错误:

  

错误C2280:&#39; std :: unique_ptr&gt; :: unique_ptr(const std :: unique_ptr&lt; _Ty,std :: default_delete&lt; _Ty&gt;&gt;&amp;)&#39;:尝试引用已删除的函数

我们不能将移动迭代器移到std::set的非const变量吗?什么可能是解决这个问题的可行办法?

1 个答案:

答案 0 :(得分:8)

为了从集合中提取仅移动元素,唯一可能的方法是使用在C ++ 17中添加的extract方法:

while (!s.empty())
    v.emplace_back(std::move(s.extract(s.begin()).value());

如果您不能使用C ++ 17,则允许修改集合的元素(例如,使用mutable,只有在确保它保留在强制排序 - 也就是说,只要它与比较器中的所有其他成员相比具有相同的结果。你可以通过提供一个比较器来执行此操作,该比较器在非空之前命令空的唯一指针(注意标准不保证这一点)并在修改后立即擦除修改后的元素:

template<class T> struct MutableWrapper { mutable T value; };
template<class T> struct MutableWrapperCompare {
  bool operator()(MutableWrapper<T> const& lhs, MutableWrapper<T> const& rhs) {
    return lhs.value && rhs.value ? lhs.value < rhs.value : rhs.value;
  }
};

int main()
{
  std::set<MutableWrapper<std::unique_ptr<const C>>, MutableWrapperCompare<std::unique_ptr<const C>>> s;
  std::vector<std::unique_ptr<const C>> v;
  while (!s.empty())
  {
    v.emplace_back(std::move(s.begin()->value));
    s.erase(s.begin());
  }
}
然而,这是相当丑陋和危险的;最好使用Boost.Container中的boost::container::set,它有C ++ 17提取方法(since 1.62.0;它was undocumented,但这只是一个疏忽,请注意extractmap)记录了相应的multimap方法。