unique_ptr - 重大改进?

时间:2009-06-05 15:43:22

标签: c++ programming-languages c++11 language-design

在实际的C ++标准中,创建满足以下规则的集合即使不是不可能也很难:

  1. 异常安全,
  2. 廉价的内部操作(在实际的STL容器中:操作是副本),
  3. 自动内存管理。
  4. 为了满足(1),集合不能存储原始指针。为了满足(2),集合必须存储原始指针。为了满足(3),集合必须按值存储对象。

    结论:这三个项目相互冲突。

    当使用shared_ptr时,不满足Item(2),因为当一个集合需要移动一个元素时,它需要进行两次调用:构造函数和析构函数。没有大规模的,memcpy() - 类似的复制/移动操作是可能的。

    我是否正确所述问题将由unique_ptrstd::move()解决?使用这些工具的馆藏将能够满足所有3个条件:

    1. 当一个集合被删除作为异常的副作用时,它将调用unique_ptr的析构函数。没有内存泄漏。
      • unique_ptr不需要任何额外的空间用于参考计数器;因此,它的主体应该与包裹的指针完全相同,
      • 我不确定,但看起来这样可以使用unique_ptrs类似的操作()移动memmove()组,
      • 即使不可能,std::move()运算符也允许移动每个unique_ptr对象而不进行构造函数/析构函数对调用。
    2. unique_ptr将拥有给定内存的独占所有权。不会发生意外的内存泄漏。
    3. 这是真的吗?使用unique_ptr的其他优点是什么?

5 个答案:

答案 0 :(得分:6)

我完全同意。最后一种处理堆分配对象的自然方法。

回答:

  

我不确定,但看起来这样可以使用unique_ptr类似的操作移动memmove()组,

有一个proposal允许这样做,但它没有进入C ++ 11标准。

答案 1 :(得分:2)

是的,你是对的。我只想补充一点,这要归功于r值引用。

答案 2 :(得分:2)

  

当一个集合作为异常的副作用被删除时,它将调用unique_ptr的析构函数。没有内存泄漏。

是的,unique_ptr的容器将满足此要求。

  

unique_ptr不需要任何额外的空间用于引用计数器;因此它的主体应该与包裹指针

完全相同

unique_ptr的大小是实现定义的。虽然unique_ptr使用它的默认析构函数的所有合理实现可能只是一个指针大小,但标准中没有保证

  

我不确定,但看起来这样可以通过使用memmove()之类的操作(?)来移动unique_ptrs组,

绝对不是。 unique_ptr不是一个微不足道的阶级;因此,它不能memmove左右。即使它是,你也不能只memmove,因为需要调用原始的析构函数。它必须是memmove后跟memset

  

即使不可能,std :: move()运算符也允许移动每个unique_ptr对象而不进行构造函数/析构函数对调用。

也不正确。运动不会使构造函数和析构函数不被调用。被销毁的unique_ptr需要销毁;这需要打电话给他们的析构函数。同样,新的unique_ptr需要调用它们的构造函数;这是对象生命周期的开始。

没有避免;这就是C ++的工作原理。

然而,这不是你应该担心的。老实说,如果你担心一个简单的构造函数/析构函数调用,你要么在代码中进行手工优化(因此编写自己的代码),要么过早地优化代码。重要的不是构造函数/析构函数是否被调用;重要的是生成的代码有多快。

  

unique_ptr将拥有给定内存的独占所有权。不会发生意外的内存泄漏。

是的,它会。

就个人而言,我说你正在做以下其中一项:

  • 对复制对象过分偏执。这是因为您考虑在容器中放置shared_ptr太昂贵了。这是C ++程序员中常见的一种疾病。这并不是说复制总是好的或者是某种东西,但是在特殊情况之外,在容器中复制shared_ptr的过程是非常荒谬的。

  • 不知道如何正确使用移动语义。如果您的物品复制成本昂贵但移动便宜......然后将它们移入容器中。当对象已经包含指针间接时,没有理由使用指针间接。只需使用对象本身的移动,而不是对象unique_ptr

  • 无视替代方案。即,Boost's pointer containers。他们似乎拥有你想要的一切。它们拥有指向其对象的指针,但在外部它们具有值语义而不是指针语义。它们是异常安全的,任何复制都会发生在指针上。没有unique_ptr构造函数/析构函数“开销”。

答案 3 :(得分:1)

看起来我在帖子中列举的三个条件可以通过Boost Pointer Container Library获得。

答案 4 :(得分:0)

这个问题说明了为什么我如此热爱Boehm garbage collector(libgc)。出于内存管理的原因,永远不需要复制任何东西,事实上,不再需要将内存所有权作为API的一部分来提及。你必须购买更多的RAM才能获得相同的CPU性能,但是你可以节省数百小时的程序员时间。你决定了。