首页 文章

聪明的指针:或谁拥有你的宝贝? [关闭]

提问于
浏览
105

C完全是关于内存所有权
阿卡“ Ownership Semantics

一块动态分配的内存的所有者负责释放该内存 . 所以这个问题真的变成了拥有记忆的人 .

在C中,所有权由RAW指针包含在内部的类型记录,因此在一个好的(IMO)C程序中,很少见[RARE并非永远]看到RAW指针传递(因为RAW指针没有推断的所有权因此我们不能告诉谁拥有记忆,因此如果没有仔细阅读文件,你无法分辨谁负责所有权) .

相反,很少看到RAW指针存储在类中,每个RAW指针都存储在自己的SMART指针包装器中 . ( N.B.: 如果你没有一个对象,你不应该存储它,因为你不知道什么时候它会超出范围并被销毁 . )

所以问题是:

  • 人们遇到什么类型的所有权语义?

  • 使用哪些标准类来实现这些语义?

  • 您觉得哪些情况有用?

让我们为每个答案保留一种语义所有权,这样他们就可以单独上下投票

摘要:

从概念上讲,智能指针很简单,而且简单易用 . 我已经看过许多尝试过的实现,但总是以某种方式打破它们,这对于随意使用和示例来说并不明显 . 因此,我建议始终使用经过良好测试的“智能指针”,而不是自己动手 . std :: auto_ptr或其中一个提升智能指针似乎涵盖了我的所有需求 .

std :: auto_ptr <T>:

单身人士拥有该物品 .
但允许转让所有权 .

用法:

这允许您定义显示所有权显式转移的接口 .

boost :: scoped_ptr <T>

单身人士拥有该物品 .
不允许转让所有权 .

用法:

用于显示明确的所有权 .
对象将被析构函数或显式重置时销毁 .

boost :: shared_ptr <T>(std :: tr1 :: shared_ptr <T>)

多个所有权 .
这是一个简单的引用计数指针 . 当引用计数达到零时,对象被销毁 .

用法:

当对象可以有多个owers,其生命周期无法在编译时确定 .

boost :: weak_ptr <T>

与shared_ptr <T>一起使用 .
在指针循环可能发生的情况下 .

用法:

用于在仅循环维护共享引用计数时停止保留对象的周期 .

11 回答

  • 1

    我认为自己无法在设计中分享所有权 . 事实上,从我的头脑中,我能想到的唯一有效的案例是Flyweight模式 .

  • 20

    从boost,还有pointer container库 . 如果您只在容器的上下文中使用对象,则它们比智能指针的标准容器更有效且更易于使用 .

    在Windows上,有COM指针(IUnknown,IDispatch和朋友),以及用于处理它们的各种智能指针(例如ATL的CComPtr和基于_com_ptr类的Visual Studio中"import"语句自动生成的智能指针) .

  • 2

    对我来说,这三种类型涵盖了我的大部分需求:

    shared_ptr - 当计数器达到零时,引用计数,解除分配

    weak_ptr - 与上面相同,但's a '奴隶'为 shared_ptr ,无法解除分配

    auto_ptr - 当创建和释放发生在同一个函数内部时,或者当对象必须被认为只有一个所有者时 . 当您将一个指针指定给另一个时,第二个指针来自第一个指针 .

    我有自己的实现,但它们也可以在 Boost 中找到 .

    我仍然通过引用传递对象(尽可能 const ),在这种情况下,被调用的方法必须假定对象仅在调用期间处于活动状态 .

    还有另一种我使用的指针,我称之为 hub_ptr . 当你拥有一个必须可以从嵌套在其中的对象访问的对象时(通常作为一个虚拟基类) . 这可以通过将 weak_ptr 传递给它们来解决,但它本身没有 shared_ptr . 因为它知道这些对象不仅仅是常规指针的模板包装器 .

  • 2

    简单C模型

    在我看到的大多数模块中,默认情况下,假设接收指针是 not 接收所有权 . 实际上,放弃指针所有权的函数/方法都非常罕见,并且在其文档中明确表达了这一事实 .

    This model assumes that the user is owner only of what he/she explicitly allocates . 其他所有内容都会自动处理(在范围退出处或通过RAII) . 这是一个类似C的模型,扩展的事实是大多数指针都由对象拥有,这些对象将自动或在需要时释放它们(主要是在所述对象破坏时),并且对象的生命持续时间是可预测的(RAII是你的朋友,再次) .

    在这个模型中,原始指针是自由流通的,并且大多数都没有危险(但如果开发人员足够聪明,他/她将尽可能使用引用) .

    • 原始指针

    • std :: auto_ptr

    • boost :: scoped_ptr

    智能指针C.模型

    在充满智能指针的代码中,用户可以希望忽略对象的生命周期 . 所有者永远不是用户代码:它是智能指针本身(RAII,再次) . The problem is that circular references mixed with reference counted smart pointers can be deadly ,所以你必须同时处理共享指针和弱指针 . 因此你仍然需要考虑所有权(弱指针很可能指向任何东西,即使它优于原始指针也是它可以告诉你的) .

    • boost :: shared_ptr

    • boost :: weak_ptr

    结论

    无论我描述的模型, unless exception, receiving a pointer is not receiving its ownershipit is still very important to know who owns who . 即使对于大量使用引用和/或智能指针的C代码 .

  • 0

    没有共享所有权 . 如果您这样做,请确保它只包含您无法控制的代码 .

    这解决了100%的问题,因为它迫使你理解一切如何相互作用 .

  • 23
    • 共享所有权

    • boost :: shared_ptr

    在多个对象之间共享资源时 . boost shared_ptr使用引用计数来确保在每个人都被finsihed时解除分配资源 .

  • 10

    std::tr1::shared_ptr<Blah> 通常是你最好的选择 .

  • 1
    • 一位所有者

    • boost :: scoped_ptr

    当您需要动态分配内存但希望确保它在块的每个出口点都被释放 .

    我发现这很有用,因为它可以很容易地重新安装,并且可以在不必担心泄漏的情况下发布

  • 1

    yasper :: ptr是一个轻量级的boost :: shared_ptr之类的替代品 . 它适用于我(现在)的小项目 .

    http://yasper.sourceforge.net/的网页中,它描述如下:

    为什么要写另一个C智能指针?已经存在几种用于C的高质量智能指针实现,最突出的是Boost指针万神殿和Loki的SmartPtr . 为了更好地比较智能指针实现以及何时使用它们,请阅读Herb Sutter的The New C:Smart(呃)指针 . 与其他库的扩展功能相比,Yasper是一个狭义聚焦的引用计数指针 . 它与Boost的shared_ptr和Loki的RefCounted / AllowConversion策略密切相关 . Yasper允许C程序员忘记内存管理而不引入Boost的大型依赖关系或者必须了解Loki的复杂策略模板 . 哲学*小(包含在单个 Headers 中)
    *简单(代码中没什么特别的,易于理解)
    *最大兼容性(替代哑指针)
    最后一点可能很危险,因为yasper允许其他实现不允许有风险(但有用)的操作(例如分配给原始指针和手动释放) . 小心,如果你知道你在做什么,只使用这些功能!

  • 2

    还有另一种经常使用的单一可转让所有者形式,它最好是 auto_ptr ,因为它避免了由于分配语义的疯狂腐败而引起的问题 .

    我说的是 swap . 任何具有合适的 swap 函数的类型都可以被视为对某些内容的智能引用,它通过交换所有权直到将所有权转移到相同类型的另一个实例 . 每个实例都保留其标识,但绑定到新内容 . 这就像一个安全可重新绑定的参考 .

    (这是一个智能参考而不是智能指针,因为您不必明确取消引用它来获取内容 . )

    这意味着auto_ptr变得不那么必要 - 它具有良好的 swap 功能 . 但是所有std容器都可以 .

  • 1
    • 一位所有者:Aka删除复制

    • std :: auto_ptr

    当对象的创建者想要明确地将所有权交给其他人时 . 这也是我给你的代码记录的方式,我不再跟踪它,所以一定要在完成后删除它 .

相关问题