谁应该拥有指针?

4
在编程中,我经常遇到以下设计选择:用户创建一个对象,并将其传递给某个在第二阶段进行处理的其他对象。
例如,你可以想象一个光线追踪器。用户创建具有特定属性的球体并调用raytracer.addTraceable(sphere)。现在,我能想到以下三种方法来做这件事:
1. 光线追踪器负责释放为球体对象分配的内存。 2. 用户需要释放为球体对象分配的内存。 3. 光线追踪器仅复制球体对象,用户和光线追踪器都释放其本地副本。
通常在这种情况下,哪种是最好的设计选择?除了我提到的选项(不包括智能指针)之外,还有其他选项吗?
PS:我在使用面向对象的方法时,在纯C中遇到了同样的问题。

为什么要排除智能指针? - Caleb
你认为显式引用计数是“智能指针”的一部分吗? - ta.speot.is
3个回答

6
使用RAII的一致性使用使这成为一个无关紧要的问题。使用智能指针,如std::shared_ptr,对象由所有指针拥有,并在最后一个指针被销毁后删除。
C实际上没有方便的方法来表达RAII习语。

所以,如果我理解正确,在我给出的例子中,光线追踪器应该处理对象的销毁,因为它是唯一能够在遇到异常时执行此操作的代码? - Grieverheart
1
@Grieverheart,使用智能指针,您不必担心谁负责对象的销毁,因为这将自动处理。 - Mark Ransom
我同意Mark Ransom的观点 - 如果适用的话,RAII将是这种情况下的选择。不幸的是,作者没有明确说明为什么他想避免使用智能指针,可能是因为他不能使用第三方库或C++11,但RAII是第四个选项,没有前三个选项的任何缺点。 - Iuri Covalisin
正如我在jxh的帖子中所评论的那样。有时我必须在非常紧密的循环中迭代对象(我正在运行物理模拟)。虽然我在问题中没有过多具体说明,但我也希望有一个适用于C语言的解决方案。 - Grieverheart
1
@Grieverheart 最佳解决方案将高度取决于您是使用C还是C++,尽管它们有相似之处和历史,但它们实际上是两种不同的语言。最好不要为两者都寻求单一解决方案。对于C而言,并没有像C++那样明显的答案。 - Mark Ransom

2
似乎你认识到智能指针可以为你解决问题,但是你似乎没有给出一个理由就否定了它。(也许是因为你的代码需要同时支持C和C++?)
如果 sphere 对象由 raytracer 对象管理,则逻辑上它拥有该对象的所有权。但是,你漏掉了一种适用于这种应用程序的选择:
用户提供要添加到 raytracer 中的对象属性,然后由该对象负责创建和销毁该对象。
那么 raytracer 就变成了工厂,而属性对象就像是建造者。

这与选项3类似,可以使用持有属性的代理类。我通常不喜欢使用智能指针,因为我编写的是性能关键代码。 - Grieverheart
你确定智能指针会成为你的应用程序瓶颈吗?我至少会尝试使用它们,进行基准测试,然后再决定是否放弃它们。 - Skalli
@Grieverheart:我不否认它们很相似,但实际上Smart Pointer有效地解决了对象所有权的问题,这正是你真正关心的问题。在紧密的循环中,可以通过使用智能指针的引用或获取裸指针本身来避免引用计数操作的开销,在使用指针时处理循环。 - jxh

1

从设计角度来看,这三种方式可能都是正确的,但总会有优缺点:

  1. C++中存在一种自动指针的所有权更改方式。缺点是代码维护,例如在光线追踪器中,您必须时刻记住对象是如何分配的,来自哪个堆。如果光线追踪器在第三方dll中实现并具有单独的堆,则在调试模式下它将失败并且在发布中会发生内存泄漏。
  2. 如果光线追踪器用户必须释放内存-它必须跟踪光线追踪器,这意味着它必须拥有所有权,具体取决于实现,它可能会增加不必要的代码复杂性。
  3. 复制对象将是一个完美的解决方案,除非必须跟踪光线追踪器中的原始球体对象更改,或者复制会影响性能或根本不可能。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接