2017-06-06 72 views
0

我一直在阅读this answer关于使用std::make_move_iterator将元素从std::vector<std::unique_ptr<T>>移动到另一个。它完美的作品:使用std :: make_move_iterator将std :: list <std :: unique_ptr >>插入另一个时出错

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 < _Ty> :: unique_ptr':无法访问在类中声明的私有成员'std :: unique_ptr < _Ty>'

但是,它的工作,如果列表中包含其他对象(如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())); 

现在,如果我用another answer从同样的问题,它采用std::back_inserterstd::move,它与两个std::vectorstd::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::unique_ptrstd::list不起作用使用std::make_move_iterator但它与std::vector如果列表元素是一个不同类型的呢?

注:我使用Visual Studio 2010中

+1

VS2 010是古老的。 [适用于我](http://rextester.com/AYXH86359)与VS2017。 –

+0

有趣......谢谢! – cbuchart

+0

我不知道它是否有任何解决方法?我有问题中提到的另一个解决方案,但我将无法从VS 2010迁移一段时间 – cbuchart

回答

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>>到另一个选项包括:

  • 使用back_inserter

    std::move(c1.begin(), c1.end(), std::back_inserter(c2)); 
    
  • 使用std::list::splice(信贷@T.C.),因为它可以用返回的列表可以直接使用,这是非常有用的通过功能:

    c2.splice(c2.end(), c1); 
    
相关问题