在实际的C ++标准中,创建满足以下规则的集合即使不是不可能也很难:
为了满足(1),集合不能存储原始指针。为了满足(2),集合必须存储原始指针。为了满足(3),集合必须按值存储对象。
结论:这三个项目相互冲突。
当使用shared_ptr
时,不满足Item(2),因为当一个集合需要移动一个元素时,它需要进行两次调用:构造函数和析构函数。没有大规模的,memcpy()
- 类似的复制/移动操作是可能的。
我是否正确所述问题将由unique_ptr
和std::move()
解决?使用这些工具的馆藏将能够满足所有3个条件:
unique_ptr
的析构函数。没有内存泄漏。unique_ptr
不需要任何额外的空间用于参考计数器;因此,它的主体应该与包裹的指针完全相同,unique_ptrs
类似的操作(?)移动memmove()
组,std::move()
运算符也允许移动每个unique_ptr
对象而不进行构造函数/析构函数对调用。unique_ptr
将拥有给定内存的独占所有权。不会发生意外的内存泄漏。这是真的吗?使用unique_ptr
的其他优点是什么?
答案 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性能,但是你可以节省数百小时的程序员时间。你决定了。