返回智能指针时的最佳做法

时间:2009-06-10 11:12:34

标签: c++ boost smart-pointers

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

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

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

但是我看到一些有经验的编码器返回原始指针,并将原始指针放在向量中。什么是正确的方法?

9 个答案:

答案 0 :(得分:23)

没有“正确”的方式。这实际上取决于具体情况。

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

如果您不确定该怎么做,您可以安全地将智能指针返回给您的来电者。当引用计数达到零时,将释放该对象。只要确保你没有一个能够永久保存智能对象指针的类,从而防止在需要时重新分配。

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

答案 1 :(得分:11)

这取决于指针的含义。

当返回shared_pointer时,你在语法上说“你将共享这个对象的所有权”,这样,如果原始容器对象在释放指针之前就死了,那么该对象仍然存在。

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

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

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

答案 2 :(得分:8)

我按照以下指南将指针参数传递给函数并返回指针:

boost::shared_ptr

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

boost::weak_ptr / raw pointer

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

std::auto_ptr

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

boost::scoped_ptr

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

与所有指导方针一样,有时会出现规则冲突或不得不弯曲,然后我会尝试使用情报。

答案 3 :(得分:7)

我通常会从工厂或类似地点返回“拥有”/“独特”智能指针,以明确谁负责清理。

此示例https://ideone.com/qJnzva显示了当调用者分配值的变量范围超出范围时,如何返回将被删除的std::unique_ptr

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

答案 4 :(得分:4)

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

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

如果出现性能问题,我会返回对象的引用和hasValidXObject方法。

答案 5 :(得分:3)

在我看来,在C ++中,你应该总是要证明使用无人看守的指针是正确的。

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

答案 6 :(得分:0)

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

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

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

答案 7 :(得分:0)

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

如果他们使用auto_ptr或boost :: scoped_ptr,他们不能使用(或返回)除原始指针之外的任何东西。这可以解释他们的编码方式,我想。

答案 8 :(得分:-1)

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

这可以避免复制。

有时您会想要返回引用,例如:

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

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

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