这是intrusive_ptr的有效用法吗?

时间:2011-04-18 23:01:22

标签: c++ boost smart-pointers

在我的代码中,我在涉及intrusive_ptrs时遵循两条规则:

  • 按值传递原始指针意味着原始指针在该函数的生命周期内保证有效。
  • 如果要在函数的生命周期之外存储和使用原始指针,则应将其存储在intrusive_ptr中。

许多互联网评论者写道,除了使用第三方代码外,shared_ptr应优先于intrusive_ptr。但是,intrusive_ptr避免了传递智能指针,因为你可以从原始指针创建一个intrusive_ptr,就像在函数的生命周期之外需要对象一样。

我只是担心我错过了一些东西,因为我读过的内容都没有说明关于intrusive_ptrs的观点,并且大多数人似乎更喜欢shared_ptrs,即使它们引入内存开销以及使用enable_shared_from_this和继承时的问题

2 个答案:

答案 0 :(得分:9)

在具有所有权语义的公共API中传递原始指针应该很少进行,并且仅在绝对必要时才进行。例如。与无法更改界面的代码连接。

在私有API中传递原始指针,例如在单个成员中是没有问题的。

考虑这三个功能:

void f(A* a);
void g(std::unique_ptr<A> a);
void h(std::shared_ptr<A> a);

f的所有权语义不明确。如果您是f的客户,则需要阅读文档以了解f是否要解除分配a,或忽略a的所有权问题。

g的所有权语义很明确。当您致电g时,您已将a的所有权转让给g,您不再对此负责。 g将取消分配a或将该资源的所有权转让给其他地方。

h的所有权语义很明确。当您致电h时,您和h成为a的共同所有者。最后一个关灯。

void q(boost::intrusive_ptr<A> a);

qh具有相同的所有权语义。主要区别在于必须存在以下自由函数:

intrusive_ptr_add_ref(A*);
intrusive_ptr_release(A*);

如果您是f的作者,并且您在a上调用了这些函数,则应记录您这样做。您的客户不一定知道您的身份。如果您是f的客户,除非您阅读其文档,否则您无法知道f是否会调用这些函数。

如果您是f的作者并且打算调用intrusive_ptr_*函数,则可以通过编码q在您的界面中明确说明。

但通常没有令人信服的理由强迫A的作者编写intrusive_ptr_*函数。您可以通过编写q来获得与h相同的所有权语义,而不会对A强加任何进一步的要求。

内存开销

如果您使用

创建shared_ptr
 shared_ptr<A> p = make_shared(arguments-to-construct-an-A);

然后您的shared_ptr将具有与intrusive_ptr完全相同的内存开销。实现将在同一内存分配中分配A和refcount。您的客户无需知道或关心您的shared_ptr是如此有效地构建的。

答案 1 :(得分:2)

intrusive_ptr确实带有其他价格:您必须使用内存管理信息来混淆您的实际设计,使得事情变得比需要的更复杂,您的项目的贡献者将不熟悉您的推理(甚至是intrusive_ptr)并且您需要更多文档。

另外:你有没有基准测试复制智能指针的开销实际上影响你的应用程序?我宁愿先使用简单版本,只在真正需要的时候引入intrusive_ptr。