C ++完全是关于内存所有权的 Aka“所有权语义”
动态分配的内存块的所有者有责任释放该内存。所以这个问题真正成为谁拥有记忆。
在C ++中,所有权都是由RAW指针包含在其中的类型记录的,因此在一个好的(IMO)C ++程序中,很少见[RARE并非绝对]看到RAW指针传递(因为RAW指针没有推断的所有权因此我们无法分辨谁拥有记忆,因此如果没有仔细阅读文件,你无法分辨谁负责所有权。
相反,很少看到RAW指针存储在类中,每个RAW指针都存储在自己的SMART指针包装器中。 ( N.B。:如果您没有对象,则不应该存储它,因为您无法知道它什么时候会超出范围并被销毁。)
所以问题是:
让每个答案保留1种语义所有权,以便可以单独上下投票
从概念上讲,智能指针很简单,而且简单易用。我已经看过许多尝试过的实现,但总是以某种方式打破它们,这对于随意使用和示例来说并不明显。因此,我建议始终使用经过良好测试的“智能指针”,而不是自己动手。 std :: auto_ptr或其中一个提升智能指针似乎可以满足我的所有需求。
单身人士拥有该物品
但允许转让所有权。
用法:
======
这允许您定义显示所有权显式转移的接口。
单身人士拥有该物品
不允许转让所有权。
用法:
======
用于显示明确的所有权
对象将被析构函数或明确重置时销毁。
多重所有权。
这是一个简单的引用计数指针。当引用计数达到零时,对象被销毁。
用法:
======
当对象可以有多个拥有者,其生命周期无法在编译时确定。
与shared_ptr< T>一起使用
在可能发生指针循环的情况下。
用法:
======
用于在仅循环维持共享引用计数时停止保留对象的周期。
答案 0 :(得分:23)
在我看到的大多数模块中,默认情况下,假设接收指针不接收所有权。事实上,放弃指针所有权的函数/方法都非常罕见,并在文档中明确表达了这一事实。
此模型假定用户仅是他/她明确分配的所有者。其他所有内容都会自动处理(在范围退出处或通过RAII)。这是一个类似C的模型,扩展的事实是大多数指针都由对象拥有,这些对象将自动或在需要时释放它们(主要是在所述对象破坏时),并且对象的生命持续时间是可预测的(RAII是你的朋友,再次)。
在这个模型中,原始指针是自由流通的,并且通常没有危险(但如果开发人员足够聪明,他/她将尽可能使用引用)。
在一个充满智能指针的代码中,用户可以希望忽略对象的生命周期。所有者永远不是用户代码:它是智能指针本身(RAII,再次)。 问题是循环引用与引用计数智能指针混合可能致命,因此您必须同时处理共享指针和弱指针。所以你仍然需要考虑所有权(弱指针很可能没有任何意义,即使它优于原始指针的优点是它可以告诉你)。
无论我描述的模型如何,除非异常,接收指针不接收其所有权和,知道谁拥有谁<仍然非常重要< / strong>即可。即使对于大量使用引用和/或智能指针的C ++代码也是如此。
答案 1 :(得分:20)
对我来说,这3种可以满足我的大部分需求:
shared_ptr
- 当计数器达到零时,引用计数,解除分配
weak_ptr
- 与上述相同,但它是shared_ptr
的“奴隶”,无法取消分配
auto_ptr
- 当创建和释放发生在同一个函数内部时,或者当对象必须被认为只有一个所有者时。当你将一个指针分配给另一个指针时,第二个指针会从第一个指定“窃取”该对象。
我有自己的实现,但它们也可以在Boost
中找到。
我仍然通过引用传递对象(尽可能const
),在这种情况下,被调用的方法必须假定对象仅在调用期间处于活动状态。
我使用了另一种指针,我称之为 hub_ptr 。当你拥有一个必须可以从嵌套在其中的对象访问的对象时(通常作为一个虚拟基类)。这可以通过将weak_ptr
传递给他们来解决,但它本身没有shared_ptr
。因为它知道这些对象不会比他长寿,所以它会将hub_ptr传递给它们(它只是常规指针的模板包装器)。
答案 2 :(得分:10)
没有共享所有权。如果您这样做,请确保它只包含您无法控制的代码。
这解决了100%的问题,因为它迫使你理解一切如何相互作用。
答案 3 :(得分:2)
在多个对象之间共享资源时。 boost shared_ptr使用引用计数来确保在每个人都被finsihed时解除分配资源。
答案 4 :(得分:2)
std::tr1::shared_ptr<Blah>
通常是您最好的选择。
答案 5 :(得分:2)
从提升开始,还有pointer container库。如果你只是在容器的上下文中使用对象,这些比智能指针的标准容器更有效,更容易使用。
在Windows上,有COM指针(IUnknown,IDispatch和朋友),以及用于处理它们的各种智能指针(例如ATL的CComPtr和由“import”语句自动生成的智能指针。 Visual Studio基于_com_ptr类)。
答案 6 :(得分:1)
当你需要动态分配内存但又想确保它在块的每个出口点都被释放时。
我发现这很有用,因为它可以很容易地重新安装,并且无需担心泄漏即可发布
答案 7 :(得分:1)
我认为自己无法在设计中拥有共享权。事实上,从我的头脑中,我能想到的唯一有效的案例是Flyweight模式。
答案 8 :(得分:1)
yasper :: ptr是一个轻量级的boost :: shared_ptr之类的替代品。它适用于我(现在)的小项目。
在http://yasper.sourceforge.net/的网页中,描述如下:
为什么要编写另一个C ++智能指针? 已经存在几个高点 优质的智能指针实现 对于C ++,最突出的是Boost 指针万神殿和Loki的SmartPtr。 为了比较智能指针 实现以及何时使用它们 适当的请阅读Herb Sutter's 新C ++:智能(呃)指针。在 与广阔的功能形成鲜明对比 其他图书馆,Yasper是一个 狭隘的重点参考计数 指针。它与之密切相关 Boost的shared_ptr和Loki的 RefCounted / AllowConversion策略。 Yasper允许C ++程序员使用 忘记没有内存管理 介绍Boost的大型 依赖或不得不了解 Loki的复杂政策模板。 理念
* small (contained in single header) * simple (nothing fancy in the code, easy to understand) * maximum compatibility (drop in replacement for dumb pointers)
最后一点可能很危险,因为 yasper允许冒险(但有用) 动作(例如分配给原始动作 指针和手动释放) 其他实现不允许。 小心,只有使用这些功能 你知道你在做什么!
答案 9 :(得分:1)
还有另一种经常使用的单一可转让所有者形式,它优于auto_ptr
,因为它避免了auto_ptr
分配语义疯狂腐败所引起的问题。
我说的只是swap
。任何具有合适swap
功能的类型都可以被视为某些内容的智能引用,直到将所有权转移到同一类型的另一个实例,通过交换为止他们。每个实例都保留其标识,但绑定到新内容。这就像是一个安全可重新绑定的参考。
(这是一个智能参考而不是智能指针,因为您不必明确取消引用它来获取内容。)
这意味着auto_ptr变得不那么必要了 - 只需要填补类型没有良好swap
功能的空白。但是所有std容器都可以。
答案 10 :(得分:0)
当对象的创建者想要明确地将所有权交给其他人时。 这也是我给你的代码记录的方式,我不再跟踪它,所以一定要在完成后删除它。