我一直在阅读this answer关于使用std::vector<std::unique_ptr<T>>
将元素从std::make_move_iterator
移动到另一个元素的问题。它完美无缺:
std::vector<std::unique_ptr<int>> c1;
std::vector<std::unique_ptr<int>> c2;
c1.push_back(std::unique_ptr<int>(new int));
c2.insert(c2.end(), std::make_move_iterator(c1.begin()), std::make_move_iterator(c1.end()));
现在我尝试将其更改为使用其他容器(std::list
):
std::list<std::unique_ptr<int>> c1;
std::list<std::unique_ptr<int>> c2;
c1.push_back(std::unique_ptr<int>(new int));
c2.insert(c2.end(), std::make_move_iterator(c1.begin()), std::make_move_iterator(c1.end()));
但编译失败了:
错误C2248:'std :: unique_ptr&lt; _Ty&gt; :: unique_ptr':无法访问类'std :: unique_ptr&lt; _Ty&gt;'中声明的私有成员
但是,如果列表包含其他对象(如std::string
):
std::list<std::string> s1;
std::list<std::string> s2;
s2.insert(s2.end(), std::make_move_iterator(s1.begin()), std::make_move_iterator(s1.end()));
现在,如果我使用std::back_inserter
和std::move
同一问题中的another answer,则它同时适用于std::vector
和std::list
:
std::list<std::unique_ptr<int>> c1;
std::list<std::unique_ptr<int>> c2;
c1.push_back(std::unique_ptr<int>(new int));
std::move(c1.begin(), c1.end(), std::back_inserter(c2));
据我所知,这个解决方案基本上是在第二个容器上插回时单独移动每个项目。
我的问题是,为什么在std::make_move_iterator
std::list
std::unique_ptr
上使用std::vector
不起作用,但是{{1}}或者列表元素属于不同类型?
注意:我正在使用Visual Studio 2010。
答案 0 :(得分:0)
核心问题是Visual Studio 2010的std::list::insert
实现并不支持移动语义。在内部,std::list::insert
调用一个名为_Insert
的方法,在VS 2010中声明如下:
void _Insert(const_iterator _Where, const _Ty& _Val)
在VS 2017中(未检查其他版本),它调用相同的方法,但声明为:
void _Insert(_Unchecked_const_iterator _Where, _Valty&&... _Val)
如图所示,VS 2017使用右值引用,因此在插入时调用std::unique_ptr
的移动构造函数。另一方面,VS 2010使用左值引用,因此在某些时候调用复制构造函数,该函数被std::unique_ptr
声明为私有,从而生成编译错误。
<强>结论强>
在VS 2010中,无法使用基于std::make_move_iterator
的解决方案,因为std::list::insert
是如何实现的。将std::list<std::unique_ptr<T>>
附加到另一个中的选项包括:
std::move(c1.begin(), c1.end(), std::back_inserter(c2));
使用std::list::splice
(归功于@T.C.),这非常有用,因为它可以直接用于函数返回的列表:
c2.splice(c2.end(), c1);