33

返回智能指针时的最佳做法是什么,例如 boost::shared_ptr?我应该按标准返回智能指针还是底层原始指针?我来自 C#,所以我倾向于总是返回智能指针,因为它感觉不错。像这样(跳过更短代码的 const 正确性):

class X
{
public:
    boost::shared_ptr<Y> getInternal() {return m_internal;}

private:
    boost::shared_ptr<Y> m_internal;
}

但是,我见过一些经验丰富的编码人员返回原始指针,并将原始指针放入向量中。正确的方法是什么?

4

9 回答 9

24

没有“正确”的方式。这真的取决于上下文。

您可以使用智能指针在内部处理内存,并在外部提供引用或原始指针。毕竟,您界面的用户不需要知道您如何在内部管理内存。在同步上下文中,这是安全且高效的。在异步上下文中,存在许多陷阱。

如果您不确定该做什么,您可以安全地将智能指针返回给您的调用者。当引用计数达到零时,对象将被释放。只需确保您没有一个永远保留对象智能指针的类,从而在需要时防止释放。

最后一点,在 C++ 中不要过度使用动态分配的对象。在许多情况下,您不需要指针并且可以处理引用和 const 引用。这样更安全,并减少了内存分配器的压力。

于 2009-06-10T11:23:30.613 回答
11

这取决于指针的含义。

返回 shared_pointer 时,您在语法上说“您将共享此对象的所有权”,这样,如果原始容器对象在您释放指针之前死亡,则该对象仍然存在。

返回一个原始指针说:“你知道这个对象,但不拥有它”。这是一种传递控制权的方式,但不会将生命周期与原始所有者联系起来。

(在一些较旧的 c 程序中,这意味着“现在删除我是你的问题”,但我强烈建议避免使用这个)

通常,默认共享为我节省了很多麻烦,但这取决于您的设计。

于 2009-06-10T11:26:44.600 回答
8

我遵循以下准则将指针参数传递给函数并返回指针:

boost::shared_ptr

API 和客户端共享此对象的所有权。shared_ptr但是,如果对象表示某种图形,则必须小心避免使用 进行循环引用。shared_ptr出于这个原因,我试图限制我的使用。

boost::weak_ptr / raw pointer

API 拥有此对象,您可以在它有效时共享它。如果客户端有可能比我使用weak_ptr的api寿命更长。

std::auto_ptr

API 正在创建一个对象,但客户端拥有该对象。这确保了返回的代码是异常安全的,并且清楚地表明所有权正在转移。

boost::scoped_ptr

用于指向存储在堆栈上或作为类成员变量的对象的指针。我尝试先使用scoped_ptr

像所有指导方针一样,有时规则会发生冲突或不得不改变,然后我会尝试使用智能。

于 2009-06-10T12:54:09.697 回答
7

我通常从工厂或类似的地方返回“拥有”/“唯一”智能指针,以明确谁负责清理。

这个例子https://ideone.com/qJnzva展示了如何返回一个std::unique_ptr当调用者分配值的变量的范围超出范围时将被删除的。

虽然智能指针确实会删除自己的指针,但保存智能指针的变量的生命周期是 100% 由调用者控制的,因此调用者决定何时删除指针。然而,由于它是一个“唯一”和“拥有”的智能指针,没有其他客户端可以控制生命周期。

于 2009-06-10T12:02:14.637 回答
4

我永远不会返回原始指针,而是返回一个weak_ptr 来告诉指针的用户他无法控制资源。

如果您返回一个weak_ptr,则应用程序中不太可能存在悬空指针。

如果存在性能问题,我将返回对对象的引用和 hasValidXObject 方法。

于 2009-06-10T11:45:31.083 回答
3

在我看来,在 C++ 中,您应该始终证明使用无保护指针的合理性。

可能有很多正当理由:需要非常高的性能、非常低的内存使用量、处理遗留库,因为指针存储的底层数据结构存在一些问题。但是[动态分配的]指针有点“邪恶”,因为你必须在每一个可能的执行路径上释放内存,你几乎肯定会忘记一个。

于 2009-06-10T11:17:23.777 回答
0

取决于你的目标。

盲目地将智能指针返回到内部数据可能不是一个好主意(这对您要解决的任务非常敏感)-您最好只提供一些在内部使用指针的 doX() 和 doY() .

另一方面,如果返回智能 ptr,您还应该考虑当对象最终无法相互破坏时,您将不会创建相互循环引用(在这种情况下,weak_ptr 可能是更好的选择)。

否则,就像上面已经提到的那样,性能/遗留代码/生命周期的考虑都应该考虑在内。

于 2009-06-10T11:22:21.473 回答
0

我不会将原始指针放在向量中。

如果他们使用 auto_ptr 或 boost::scoped_ptr,他们只能使用(或返回)原始指针。我猜这可以解释他们的编码方式。

于 2009-06-10T11:22:39.053 回答
-2

const boost::shared_ptr &getInternal() {return m_internal;}

这样可以避免复制。

有时您希望返回参考,例如:

  • Y &operator*() { return *m_internal; }
  • const Y &operator*() const { return *m_internal; }

仅当引用将被立即使用和丢弃时,这也很好。原始指针也是如此。返回一个weak_ptr 也是一种选择。

这4个很好,取决于目标。这个问题需要更广泛的讨论。

于 2009-06-11T13:36:58.733 回答