21

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

  1. 异常安全,
  2. 廉价的内部操作(在实际的 STL 容器中:操作是副本),
  3. 自动内存管理。

为了满足 (1),集合不能存储原始指针。为了满足 (2),集合必须存储原始指针。为了满足 (3),集合必须按值存储对象。

结论:三项相互冲突。

使用 s时不会满足第 (2) 项,shared_ptr因为当集合需要移动元素时,它需要进行两次调用:构造函数和析构函数。不可能进行大规模memcpy()的复制/移动操作。

我是否正确,所描述的问题将由unique_ptrand解决std::move()?使用这些工具的集合将能够满足所有 3 个条件:

  1. 当一个集合作为异常的副作用而被删除时,它将调用unique_ptr' 析构函数。没有内存泄漏。
    • unique_ptr参考计数器不需要任何额外空间;因此它的主体应该与包装指针的大小完全相同,
    • 我不确定,但看起来这允许unique_ptrs通过使用memmove()类似操作()来移动组,
    • 即使不可能,std::move()操作员也将允许移动每个unique_ptr对象,而无需调用构造函数/析构函数对。
  2. unique_ptr将拥有给定内存的独占所有权。不会发生意外的内存泄漏。

这是真的?使用的其他优点是unique_ptr什么?

4

5 回答 5

6

我完全同意。终于有了一种处理堆分配对象的自然方式。

回答:

我不确定,但看起来这允许unique_ptr通过使用memmove()类似的操作来移动 s 组,

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

于 2009-06-05T16:31:36.853 回答
2

是的你是对的。由于 r 值引用,我只会添加这是可能的。

于 2009-06-05T15:51:30.443 回答
2

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

是的,一个容器unique_ptr将满足这一点。

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

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

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

绝对不。unique_ptr不是一个平凡的类;因此,它不能在memmove周围。即使是这样,您也不能只memmove使用它们,因为需要调用原件的析构函数。它必须是 amemmove后跟 a memset

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

也不正确。运动不会使构造函数和析构函数不被调用。正在被销毁的unique_ptr's 需要被销毁;这需要调用它们的析构函数。同样, newunique_ptr需要调用它们的构造函数;这就是对象生命周期的开始。

这是无法避免的。这就是 C++ 的工作原理。

但是,这不是您应该担心的。老实说,如果您关心一个简单的构造函数/析构函数调用,那么您要么处于应该手动优化的代码中(并因此编写自己的代码),要么过早地优化您的代码。重要的不是构造函数/析构函数是否被调用;重要的是生成的代码有多快。

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

是的,它会。

就个人而言,我会说您正在执行以下操作之一:

  • 对复制对象过于偏执。这证明了您认为将 ashared_ptr放入容器中的副本成本太高。这在 C++ 程序员中是一个非常普遍的毛病。这并不是说复制总是好的什么的,但是shared_ptr除了特殊情况之外,痴迷于在容器中复制 a 是荒谬的。

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

  • 无视替代品。即Boost 的指针容器。他们似乎拥有你想要的一切。它们拥有指向其对象的指针,但在外部它们具有值语义而不是指针语义。它们是异常安全的,并且任何复制都使用指针进行。没有unique_ptr构造函数/析构函数“开销”。

于 2012-08-09T11:22:11.830 回答
1

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

于 2009-06-05T20:06:59.520 回答
0

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

于 2009-06-05T21:56:27.537 回答