ptr在stl集合中安全使用?

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

假设我们有两个集合:

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! 时刻。


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

潜在的问题是移动和复制有什么区别。 我不会跳入技术/标准语言,我们只需简单地做:

  • 复制:创建另一个相同的对象(或者至少应该比较一个相同的对象)
  • 移动:取一个物体并放在另一个位置
  • 正如您所说,可以实现移动复制:在新位置创建副本并丢弃原始文件。 但是这里有两个问题。 一个是性能,第二个是关于用于RAII的对象:这两个中的哪一个应该拥有所有权?

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

  • 很清楚哪个对象拥有所有权:新的对象,因为原始对象将被丢弃
  • 因此没有必要复制指向的资源,这可以提高效率
  • auto_ptrunique_ptr就是一个很好的例子。

    有了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)
    

    所以你可以在容器中使用unique_ptr (与auto_ptr不同),但是一些操作是不可能的,因为它们涉及到类型不支持的复制。

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


    unique_ptr正在使用其移动构造函数进行移动。 unique_ptr是可移动的,但不是CopyConstructable。

    这里有一篇关于右值引用的文章。 如果你还没有读过它们,或者感到困惑,请看看!


    std::sort只能在移动操作和不复制的情况下工作,只要每个对象在任何给定时间只有一个活动副本。 由于原则上你可以暂时分配另一个数组,并将所有对象移动到重新排序的位置,这是一个比在原地更弱的要求。

    例如std::vector<std::unique_ptr<T>>超过了它的容量,它会为更大的向量分配存储空间,然后将所有对象从旧存储设备移动到新存储设备。 这不是一个就地操作,但它是完全有效的。

    事实证明,快速排序和堆排序等排序算法实际上可以毫无困难地在现场正常工作。 快速排序的分区例程在内部使用std :: swap,这将作为所涉及对象的移动操作。 当选择一个数据透视表时,一个技巧就是将它与该范围内的第一个元素进行交换,这样在分区完成之前,它将永远不会移动。

    链接地址: http://www.djcxy.com/p/59669.html

    上一篇: ptr be used safely in stl collections?

    下一篇: How to add a certificate to the default Firefox profile on RHEL 6?