所以,unique_ptr可以安全地使用在stl集合? [英] So can unique_ptr be used safely in stl collections?

查看:292
本文介绍了所以,unique_ptr可以安全地使用在stl集合?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我对unique_ptr和rvalue move哲学感到困惑。



我们有两个集合:

  std :: vector< std :: auto_ptr< int>> autoCollection; 
std :: vector< std :: unique_ptr< int>> uniqueCollection;

现在我希望以下内容失败,因为没有人知道算法在内部做什么,可能会创建内部数据库副本等,从而从auto_ptr中剥离所有权:

  std :: sort(autoCollection.begin ),autoCollection.end()); 

我得到这个。



但是我这样做:

  std :: sort(uniqueCollection.begin(),uniqueCollection.end()); 

然后编译。我不明白为什么。我不认为unique_ptrs可以复制。这是否意味着不能采用枢轴值,因此排序效率较低?或者是这个枢轴实际上是一个动作,其实是与auto_ptrs的集合一样危险,并且应该被编译器禁止?



我想我缺少一些关键一条信息,所以我急切地等待有人给我aha!

解决方案

我认为这是一个哲学问题而不是技术问题:)



潜在的问题是Move和Copy之间的区别。我不会跳到技术/标准的语言,让我们这样做:




  • 复制:创建另一个相同的对象


$ b 正如你所说,可以实现移动的复制:创建一个副本到新的位置,并放弃原来的。但是有两个问题。一个是性能,第二个是关于用于RAII的对象:哪两个应该拥有所有权?



一个合适的Move构造函数解决了2个问题:




  • 很清楚哪个对象具有所有权:新的对象,因为原始对象将被丢弃

  • 不必复制指向的资源,从而提高效率



auto_ptr

使用 auto_ptr code>你有一个螺丝的复制语义:原来和副本不比较相等。你可以使用它的移动语义,但是有一个风险,你会失去指向某个地方的对象。



另一方面, unique_ptr 正是这样:它保证资源的唯一所有者,从而避免复制和随后的不可避免的删除问题。并且在编译时也保证了无拷贝。因此,只要不尝试复制初始化,它就适用于容器。

  typedef std :: unique_ptr< int> ; unique_t; 
typedef std :: vector< unique_t> vector_t;

vector_t vec1; // fine
vector_t vec2(5,unique_t(new Foo)); //错误(复制)
vector_t vec3(vec1.begin(),vec1.end()); //错误(复制)
vector_t vec3(make_move_iterator(vec1.begin()),make_move_iterator(vec1.end()));
//由sehe提供

std :: sort(vec1.begin(),vec1.end()); // fine,因为使用移动赋值运算符

std :: copy(vec1.begin(),vec1.end(),std :: back_inserter(vec2)); //错误(复制)

因此您使用 unique_ptr (不像 auto_ptr ),但是一些操作是不可能的,因为它们涉及类型不支持的复制。



不幸的是,Visual Studio可能在执行标准方面相当松懈,并且还有一些扩展,您需要禁用它们以确保代码的可移植性。不要用它来检查标准:)


I am confused with unique_ptr and rvalue move philosophy.

Let's say we have two collections:

std::vector<std::auto_ptr<int>> autoCollection;
std::vector<std::unique_ptr<int>> uniqueCollection;

Now I would expect the following to fail, as there is no telling what the algorithm is doing internally and maybe making internal pivot copies and the like, thus ripping away ownership from the auto_ptr:

std::sort(autoCollection.begin(), autoCollection.end());

I get this. And the compiler rightly disallows this happening.

But then I do this:

std::sort(uniqueCollection.begin(), uniqueCollection.end());

And this compiles. And I do not understand why. I did not think unique_ptrs could be copied. Does this mean a pivot value cannot be taken, so the sort is less efficient? Or is this pivot actually a move, which in fact is as dangerous as the collection of auto_ptrs, and should be disallowed by the compiler?

I think I am missing some crucial piece of information, so I eagerly await someone to supply me with the aha! moment.

解决方案

I think it's more a question of philosophy than technic :)

The underlying question is what is the difference between Move and Copy. I won't jump into technical / standardista language, let's do it simply:

  • Copy: create another identical object (or at least, one which SHOULD compare equal)
  • Move: take an object and put it in another location

As you said, it is possible to implement Move in term of Copy: create a copy into the new location and discard the original. However there are two issues there. One is of performance, the second is about objects used for RAII: which of the two should have ownership ?

A proper Move constructor solves the 2 issues:

  • It is clear which object has ownership: the new one, since the original will be discarded
  • It is thus unnecessary to copy the resources pointed to, which allows for greater efficiency

The auto_ptr and unique_ptr are a very good illustration of this.

With an auto_ptr you have a screwed Copy semantic: the original and the copy don't compare equal. You could use it for its Move semantic but there is a risk that you'll lose the object pointed to somewhere.

On the other hand, the unique_ptr is exactly that: it guarantees a unique owner of the resource, thus avoiding copying and the inevitable deletion issue that would follow. And the no-copy is guaranteed at compile-time too. Therefore, it's suitable in containers as long as you don't try to have copy initialization.

typedef std::unique_ptr<int> unique_t;
typedef std::vector< unique_t > vector_t;

vector_t vec1;                           // fine
vector_t vec2(5, unique_t(new Foo));     // Error (Copy)
vector_t vec3(vec1.begin(), vec1.end()); // Error (Copy)
vector_t vec3(make_move_iterator(vec1.begin()), make_move_iterator(vec1.end()));
    // Courtesy of sehe

std::sort(vec1.begin(), vec1.end()); // fine, because using Move Assignment Operator

std::copy(vec1.begin(), vec1.end(), std::back_inserter(vec2)); // Error (copy)

So you can use unique_ptr in a container (unlike auto_ptr), but a number of operations will be impossible because they involve copying which the type does not support.

Unfortunately Visual Studio may be quite lax in the enforcement of the standard and also has a number of extensions that you would need to disable to ensure portability of the code... don't use it to check the standard :)

这篇关于所以,unique_ptr可以安全地使用在stl集合?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆