从 std::set 中提取仅移动类型
Extracting move only type from std::set
我有一个 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 上出现以下错误:
error C2280: 'std::unique_ptr>::unique_ptr(const std::unique_ptr<_Ty,std::default_delete<_Ty>> &)': attempting to reference a deleted function
我们不能将迭代器从 std::set
移动到非常量变量吗?什么是这个问题的可行解决方案?
为了从集合中提取只移动元素,唯一的可能是使用 extract
方法,该方法是在 C++17 中添加的:
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, which has the C++17 extract method (since 1.62.0; it was undocumented 中的 boost::container::set
,但这只是一个疏忽,请注意 map
和 multimap
记录了相应的 extract
方法)。
我有一个 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 上出现以下错误:
error C2280: 'std::unique_ptr>::unique_ptr(const std::unique_ptr<_Ty,std::default_delete<_Ty>> &)': attempting to reference a deleted function
我们不能将迭代器从 std::set
移动到非常量变量吗?什么是这个问题的可行解决方案?
为了从集合中提取只移动元素,唯一的可能是使用 extract
方法,该方法是在 C++17 中添加的:
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, which has the C++17 extract method (since 1.62.0; it was undocumented 中的 boost::container::set
,但这只是一个疏忽,请注意 map
和 multimap
记录了相应的 extract
方法)。