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

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

  • 许多Internet评论员已经写道,与第三方代码相比,shared_ptr应该比intrusive_ptr更可取。但是,intrusive_ptr避免了智能指针的传递,因为您可以从原始指针创建intrusive_ptr,就像在函数生命周期之外需要该对象时一样。

    我只是担心我会丢失某些东西,因为我读到的东西都没有涉及到intrusive_ptrs,而且大多数人似乎更喜欢shared_ptrs,即使它们在使用enable_shared_from_this和继承时会带来内存开销以及问题。

    最佳答案

    只有在绝对必要的情况下,才应该在具有所有权语义的公共(public)API中传递原始指针。例如。与您不能更改其接口(interface)的代码接口(interface)。

    在私有(private)API中传递原始指针,例如单个类(class)内的成员没有问题。

    请考虑以下三个功能:

    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);
    
    q具有与h相同的所有权语义。主要区别在于必须存在以下自由函数:
    intrusive_ptr_add_ref(A*);
    intrusive_ptr_release(A*);
    

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

    如果您是intrusive_ptr_*的作者,并且打算调用q函数,则可以通过对A进行编码来在界面中将其明确显示。

    但是通常没有令人信服的理由强加给intrusive_ptr_*的作者来编写q函数。而且,您可以通过编写h来获得与oj​​it_code相同的所有权语义,而无需在A上对施加任何进一步的要求。

    内存开销

    如果您使用以下方法创建shared_ptr:
     shared_ptr<A> p = make_shared(arguments-to-construct-an-A);
    

    那么您的shared_ptr将具有与intrusive_ptr完全相同的内存开销。该实现将在同一内存分配中分配A和refcount。您的客户不需要知道或关心您的shared_ptr如此高效地构造。

    09-09 18:30