那么unique_ptr可以在stl集合中安全使用吗?

2024-03-01

我对 unique_ptr 和右值移动哲学感到困惑。

假设我们有两个集合:

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 的集合一样危险,并且应该被编译器禁止?

我认为我错过了一些重要的信息,所以我热切地等待有人向我提供啊哈!片刻。


我认为这更多的是哲学问题而不是技术问题:)

根本问题是移动和复制之间有什么区别。我不会跳入技术/标准语言,让我们简单地做一下:

  • 复制:创建另一个相同的对象(或者至少是一个应该比较相等的对象)
  • 移动:取出一个物体并将其放在另一个位置

正如您所说,可以根据复制来实现移动:在新位置创建一个副本并丢弃原始位置。然而,这里有两个问题。一是性能,二是用于 RAII 的对象:两者中哪一个应该拥有所有权?

正确的 Move 构造函数可以解决两个问题:

  • 很清楚哪个对象拥有所有权:新对象,因为原始对象将被丢弃
  • 因此无需复制指向的资源,从而提高效率

The auto_ptr and unique_ptr是一个很好的例证。

With an auto_ptr你有一个扭曲的复制语义:原始文件和副本不相等。您可以将其用于其移动语义,但存在丢失指向某处的对象的风险。

另一方面,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));     // 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在容器中(不同于auto_ptr),但许多操作是不可能的,因为它们涉及类型不支持的复制。

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

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

那么unique_ptr可以在stl集合中安全使用吗? 的相关文章