我真的想将unique_ptr
从一个std::set
移到另一个#include <memory>
#include <algorithm>
#include <set>
int main()
{
std::set<std::unique_ptr<int>> a;
std::set<std::unique_ptr<int>> b;
a.insert({0, std::unique_ptr<int>(new int(42))});
std::move(a.begin(), a.end(), std::inserter(b, b.end()));
}
:
[root@localhost ~]# g++ test.cpp -std=c++11 -o test
In file included from /usr/include/c++/4.8.2/set:60:0,
from test.cpp:2:
/usr/include/c++/4.8.2/bits/stl_tree.h: In instantiation of ‘std::_Rb_tree_node<_Val>::_Rb_tree_node(_Args&& ...) [with _Args = {const std::unique_ptr<int, std::default_delete<int> >&}; _Val = std::unique_ptr<int>]’:
/usr/include/c++/4.8.2/ext/new_allocator.h:120:4: required from ‘void __gnu_cxx::new_allocator<_Tp>::construct(_Up*, _Args&& ...) [with _Up = std::_Rb_tree_node<std::unique_ptr<int> >; _Args = {const std::unique_ptr<int, std::default_delete<int> >&}; _Tp = std::_Rb_tree_node<std::unique_ptr<int> >]’
/usr/include/c++/4.8.2/bits/alloc_traits.h:254:4: required from ‘static typename std::enable_if<std::allocator_traits<_Alloc>::__construct_helper<_Tp, _Args>::value, void>::type std::allocator_traits<_Alloc>::_S_construct(_Alloc&, _Tp*, _Args&& ...) [with _Tp = std::_Rb_tree_node<std::unique_ptr<int> >; _Args = {const std::unique_ptr<int, std::default_delete<int> >&}; _Alloc = std::allocator<std::_Rb_tree_node<std::unique_ptr<int> > >; typename std::enable_if<std::allocator_traits<_Alloc>::__construct_helper<_Tp, _Args>::value, void>::type = void]’
/usr/include/c++/4.8.2/bits/alloc_traits.h:393:57: required from ‘static decltype (_S_construct(__a, __p, (forward<_Args>)(std::allocator_traits::construct::__args)...)) std::allocator_traits<_Alloc>::construct(_Alloc&, _Tp*, _Args&& ...) [with _Tp = std::_Rb_tree_node<std::unique_ptr<int> >; _Args = {const std::unique_ptr<int, std::default_delete<int> >&}; _Alloc = std::allocator<std::_Rb_tree_node<std::unique_ptr<int> > >; decltype (_S_construct(__a, __p, (forward<_Args>)(std::allocator_traits::construct::__args)...)) = <type error>]’
/usr/include/c++/4.8.2/bits/stl_tree.h:408:36: required from ‘std::_Rb_tree_node<_Val>* std::_Rb_tree<_Key, _Val, _KeyOfValue, _Compare, _Alloc>::_M_create_node(_Args&& ...) [with _Args = {const std::unique_ptr<int, std::default_delete<int> >&}; _Key = std::unique_ptr<int>; _Val = std::unique_ptr<int>; _KeyOfValue = std::_Identity<std::unique_ptr<int> >; _Compare = std::less<std::unique_ptr<int> >; _Alloc = std::allocator<std::unique_ptr<int> >; std::_Rb_tree<_Key, _Val, _KeyOfValue, _Compare, _Alloc>::_Link_type = std::_Rb_tree_node<std::unique_ptr<int> >*]’
/usr/include/c++/4.8.2/bits/stl_tree.h:1023:66: required from ‘std::_Rb_tree<_Key, _Val, _KeyOfValue, _Compare, _Alloc>::iterator std::_Rb_tree<_Key, _Val, _KeyOfValue, _Compare, _Alloc>::_M_insert_(std::_Rb_tree<_Key, _Val, _KeyOfValue, _Compare, _Alloc>::_Base_ptr, std::_Rb_tree<_Key, _Val, _KeyOfValue, _Compare, _Alloc>::_Base_ptr, _Arg&&) [with _Arg = const std::unique_ptr<int>&; _Key = std::unique_ptr<int>; _Val = std::unique_ptr<int>; _KeyOfValue = std::_Identity<std::unique_ptr<int> >; _Compare = std::less<std::unique_ptr<int> >; _Alloc = std::allocator<std::unique_ptr<int> >; std::_Rb_tree<_Key, _Val, _KeyOfValue, _Compare, _Alloc>::iterator = std::_Rb_tree_iterator<std::unique_ptr<int> >; std::_Rb_tree<_Key, _Val, _KeyOfValue, _Compare, _Alloc>::_Base_ptr = std::_Rb_tree_node_base*]’
/usr/include/c++/4.8.2/bits/stl_tree.h:1482:33: required from ‘std::_Rb_tree<_Key, _Val, _KeyOfValue, _Compare, _Alloc>::iterator std::_Rb_tree<_Key, _Val, _KeyOfValue, _Compare, _Alloc>::_M_insert_unique_(std::_Rb_tree<_Key, _Val, _KeyOfValue, _Compare, _Alloc>::const_iterator, _Arg&&) [with _Arg = const std::unique_ptr<int>&; _Key = std::unique_ptr<int>; _Val = std::unique_ptr<int>; _KeyOfValue = std::_Identity<std::unique_ptr<int> >; _Compare = std::less<std::unique_ptr<int> >; _Alloc = std::allocator<std::unique_ptr<int> >; std::_Rb_tree<_Key, _Val, _KeyOfValue, _Compare, _Alloc>::iterator = std::_Rb_tree_iterator<std::unique_ptr<int> >; std::_Rb_tree<_Key, _Val, _KeyOfValue, _Compare, _Alloc>::const_iterator = std::_Rb_tree_const_iterator<std::unique_ptr<int> >]’
/usr/include/c++/4.8.2/bits/stl_tree.h:1722:37: required from ‘void std::_Rb_tree<_Key, _Val, _KeyOfValue, _Compare, _Alloc>::_M_insert_unique(_II, _II) [with _InputIterator = const std::unique_ptr<int>*; _Key = std::unique_ptr<int>; _Val = std::unique_ptr<int>; _KeyOfValue = std::_Identity<std::unique_ptr<int> >; _Compare = std::less<std::unique_ptr<int> >; _Alloc = std::allocator<std::unique_ptr<int> >]’
/usr/include/c++/4.8.2/bits/stl_set.h:518:4: required from ‘void std::set<_Key, _Compare, _Alloc>::insert(_InputIterator, _InputIterator) [with _InputIterator = const std::unique_ptr<int>*; _Key = std::unique_ptr<int>; _Compare = std::less<std::unique_ptr<int> >; _Alloc = std::allocator<std::unique_ptr<int> >]’
/usr/include/c++/4.8.2/bits/stl_set.h:530:9: required from ‘void std::set<_Key, _Compare, _Alloc>::insert(std::initializer_list<_Tp>) [with _Key = std::unique_ptr<int>; _Compare = std::less<std::unique_ptr<int> >; _Alloc = std::allocator<std::unique_ptr<int> >]’
test.cpp:9:49: required from here
/usr/include/c++/4.8.2/bits/stl_tree.h:140:49: error: use of deleted function ‘std::unique_ptr<_Tp, _Dp>::unique_ptr(const std::unique_ptr<_Tp, _Dp>&) [with _Tp = int; _Dp = std::default_delete<int>]’
_M_value_field(std::forward<_Args>(__args)...) { }
^
In file included from /usr/include/c++/4.8.2/memory:81:0,
from test.cpp:1:
/usr/include/c++/4.8.2/bits/unique_ptr.h:273:7: error: declared here
unique_ptr(const unique_ptr&) = delete;
^
然而,我在CentOS 7上的GCC 4.8.5明显不满意:
import a import b
我需要做些什么来完成这项工作?
答案 0 :(得分:12)
你基本上不能在C ++ 14中这样做,因为一个集合的元素是const
。由于移动是一种修改操作,因此您需要某种方式来获取对元素的非const
访问权限,而且根本无法做到这一点。
但 能够使用新的merge()
成员函数在C ++ 17中执行此操作:
b.merge(std::move(a));
同样,会有一个extract()
成员函数,它会删除并授予您对单个节点的非const
访问权限。
当然,您总是可以使用类似的类型(h / t by T.C.):
struct Hack {
mutable std::unique_ptr<T> p;
T* raw_ptr;
bool operator<(Hack const& h) const {
// implemented in terms of the raw ptr
// not the unique ptr
}
};
从p
移动现在是安全的(它是可变的)并且只要你只是移动(而不是reset()
)并根据原始指针实现排序,那么你也应该保留集合顺序。你现在必须存储两个指针,但这应该避免在C ++ 11中使用UB。
答案 1 :(得分:4)
std :: set的元素是 const ,主要是因为std :: set按元素的值排序。更改值可能会改变排序 - 因此 - 将破坏std :: set的内部表示。
将std :: unique_ptr移出std :: set肯定会使std :: set无法使用。
答案 2 :(得分:0)
以下是在g ++ 4.8.2中使用C ++ 11执行此操作的一种方法:
#include <iostream>
#include <set>
#include <memory>
#include <utility>
// One possible solution:
template <typename Type>
void move_set_unique_ptr(
std::set<std::unique_ptr<Type>> & source,
std::set<std::unique_ptr<Type>> & destination
) {
for ( const std::unique_ptr<Type> & source_unique_ptr : source ) {
destination.insert(
std::move( const_cast<std::unique_ptr<Type> &>( source_unique_ptr ) )
);
}
source.clear();
}
// Not part of a solution ... just for use with std::cout:
template <typename Type>
std::ostream & operator << (
std::ostream & o,
const std::set<std::unique_ptr<Type>> & s
);
int main() {
using type = int;
std::set<std::unique_ptr<type>> a;
std::set<std::unique_ptr<type>> b;
// std::make_unique<T> is not available in C++11
a.insert( nullptr );
a.insert( std::unique_ptr<type>( new type{ 62 } ) );
a.insert( std::unique_ptr<type>( new type{ 42 } ) );
a.insert( std::unique_ptr<type>( new type{ 22 } ) );
b.insert( std::unique_ptr<type>( new type{ 41 } ) );
b.insert( std::unique_ptr<type>( new type{ 42 } ) );
b.insert( std::unique_ptr<type>( new type{ 43 } ) );
b.insert( nullptr );
std::cout << "a: " << a << '\n';
std::cout << "b: " << b << '\n';
move_set_unique_ptr(a, b);
std::cout << "a: " << a << '\n';
std::cout << "b: " << b << '\n';
}
// Not part of a solution ... just for use with std::cout:
template <typename Type>
std::ostream & operator << (
std::ostream & o,
const std::set<std::unique_ptr<Type>> & s
) {
auto i = std::begin( s );
auto end = std::end( s );
o << '{';
if ( i != end ) {
auto print = [ &o, &i ]() {
o << i->get() << ": " << ( *i == nullptr ? Type{} : **i );
};
o << ' '; print();
for ( ++i; i != end; ++i ) {
o << ", "; print();
}
o << ' ';
}
o << '}';
return o;
}
这将输出如下内容:
a: { 0: 0, 0x8f3c50: 62, 0x8f3ca0: 42, 0x8f3cf0: 22 }
b: { 0: 0, 0x8f3d40: 41, 0x8f3d90: 42, 0x8f3de0: 43 }
a: {}
b: { 0: 0, 0x8f3c50: 62, 0x8f3ca0: 42, 0x8f3cf0: 22, 0x8f3d40: 41, 0x8f3d90: 42, 0x8f3de0: 43 }