这是 intrusive_ptr 的有效使用吗?

发布于 2024-11-02 10:40:09 字数 417 浏览 5 评论 0原文

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

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

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

我只是担心我遗漏了一些东西,因为我读过的任何内容都没有说明有关 intrusive_ptrs 的这一点,而且大多数人似乎更喜欢共享指针,即使它们会带来内存开销,并且在使用 enable_shared_from_this 和继承时也会出现问题。

Within my code I follow two rules when it comes to intrusive_ptrs:

  • Passing a raw pointer by value implies that the raw pointer is guaranteed to be valid during the lifetime of that function.
  • If the raw pointer is to be stored and used beyond the lifetime of the function, it should be stored in an intrusive_ptr.

Many Internet commenters have written that shared_ptr should be preferred over intrusive_ptr except when working with third party code. However, intrusive_ptr obviates passing around smart pointers since you can create an intrusive_ptr from a raw pointer, as when the object is needed beyond the lifetime of the function.

I'm just concerned that I'm missing something because nothing that I've read has made this point about intrusive_ptrs, and that most people seem to prefer shared_ptrs even though they introduce memory overhead and also problems when using enable_shared_from_this and inheritance.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

在风中等你 2024-11-09 10:40:09

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

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

考虑这三个函数:

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

f 的所有权语义不清楚。如果您是 f 的客户,您需要阅读文档以了解 f 是否要释放 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_* 函数。您可以通过编写 h 来获得与 q 相同的所有权语义,而无需对 A 强加任何进一步的要求。

关于内存开销

如果您使用以下方式创建 shared_ptr

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

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

Passing a raw pointer around in a public API that has ownership semantics should be done only rarely, and only when absolutely necessary. E.g. interfacing with code whose interface you can not change.

Passing around a raw pointer in a private API, e.g. within the members of a single class is no problem.

Consider these three functions:

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

The ownership semantics of f is not clear. If you are the client of f you need to read the documentation to find out if f is going to deallocate a, or ignore ownership issues for a.

The ownership semantics of g is clear. When you call g you pass the ownership of a to g and you are no longer responsible for it. g will either deallocate a or transfer ownership of that resource somewhere else.

The ownership semantics of h is clear. When you call h, you and h become co-owners of a. Last one out turns off the lights.

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

q has the same ownership semantics as h. The main difference is that the following free functions must exist:

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

If you are the author of f and you call these functions on a, you should document that you do so. Your clients won't necessarily know that you are. And if you are a client of f, you have no way of knowing if f will call these functions unless you read its documentation.

If you are the author of f and you intend on calling the intrusive_ptr_* functions, you can make that explicit in your interface by coding q instead.

But usually there is not a compelling reason to impose on the author of A to write the intrusive_ptr_* functions. And you can get the same ownership semantics as q by writing h instead, without imposing any further requirements on A.

On Memory Overhead

If you create your shared_ptr with:

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

then your shared_ptr will have the exact same memory overhead as an intrusive_ptr. The implementation will allocate the A and the refcount in the same memory allocation. Your clients need not know or care that your shared_ptr was constructed so efficiently.

╭ゆ眷念 2024-11-09 10:40:09

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

另外:您是否曾经对复制智能指针的开销实际上影响您的应用程序进行过基准测试?我宁愿先使用简单版本,并且仅在真正必要时才引入 intrusive_ptr 。

intrusive_ptr does come with other prices: you have to clutter your actual design with memory management information, you are making things more complicated than required, contributors to your project wont be familiar with your reasoning (and even intrusive_ptr) and you need more documentation.

Also: have you ever benchmarked that the overhead of copying smart pointers is actually affecting your application? I'd rather go with the simple version first and would introduce intrusive_ptr only when really necessary.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文