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

tun*_*unc 3 c++ stl move set c++11

我有一个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));
}
Run Code Online (Sandbox Code Playgroud)

这会在VS2017上出现以下错误:

错误C2280:'std :: unique_ptr> :: unique_ptr(const std :: unique_ptr <_Ty,std :: default_delete <_Ty >>&)':尝试引用已删除的函数

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

eca*_*mur 8

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

while (!s.empty())
    v.emplace_back(std::move(s.extract(s.begin()).value());
Run Code Online (Sandbox Code Playgroud)

如果你不能使用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());
  }
}
Run Code Online (Sandbox Code Playgroud)

然而,这是相当丑陋和危险的; 你会使用会更好boost::container::setBoost.Container,其具有C++ 17提取方法(自1.62.0 ;它没有记录,但是这仅仅是一个疏忽,记下相应的extract方法被用于记录mapmultimap).