在库接口中提供对weak_ptr的访问是否明智?

发布于 2024-07-15 00:25:24 字数 446 浏览 10 评论 0原文

我编写了一个库,公开了对几种相关对象类型的引用。 所有这些对象的生命周期都由库通过 boost::shared_ptr 在内部管理。

库的用户还可以根据库的性质了解任何公开对象的生命周期。 因此它们可以存储指针或保留对这些对象的引用。 他们这样做并知道这些对象何时不再有效是合理的。

但我对强迫我的用户讲道理感到内疚。

让库向其对象公开 weak_ptr 是否可以接受? 其他库是否这样做过?

我已经分析了该库在应用程序中的使用情况,并发现它对于任务至关重要,无法专门公开 weak_ptr

让匹配的 API 函数暴露一个引用或一个weak_ptr,或者让任何对象能够向自身暴露一个weak_ptr,这会是更明智的做法吗?

I have written a library that exposes references to several related object types. All of these objects have their lifetimes managed by the library internally via boost::shared_ptr

A user of the library would also be able to know, by nature of the library, the lifetimes of any of the exposed objects. So they could store pointers or keep references to these objects. It would be reasonable for them to do this and know when those objects are no longer valid.

But I feel guilty forcing my users to be reasonable.

Is it acceptable to have a library expose weak_ptr's to its objects? Have other libraries done this?

I have profiled this library's usage in apps and have found it to be too mission-critical to expose weak_ptr exclusively.

Would it be wiser to have matching API functions expose either a reference or a weak_ptr or to make any object capable of exposing a weak_ptr to itself?

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

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

发布评论

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

评论(5

笛声青案梦长安 2024-07-22 00:25:24

如果库的用户已经可以直接访问 smart_ptr,那么他们就已经可以访问 weak_ptr,只需通过相应的 weak_ptr 即可> 的构造函数。 但如果 smart_ptr 都在库内部,那就是另一回事了。

在这种情况下,我建议除了您的库提供的任何其他访问之外,还让每个对象将 weak_ptr 传递给自身。 这为用户提供了最大的灵活性:如果他们需要 weak_ptr,他们可以立即访问它; 如果他们需要一个shared_ptr,他们可以轻松获得; 如果他们只需要访问对象本身,他们可以完全忽略智能指针。

当然,我不知道你们的图书馆是做什么的,也不知道它是如何使用或设计的。 这可能会改变我的建议。

If the smart_ptrs are already directly accessible to the library's users, then they've already got access to the weak_ptrs, simply via the corresponding weak_ptr's constructor. But if the smart_ptrs are all internal to the library, that's a different story.

In that case, I'd recommend letting each object pass out weak_ptrs to itself, in addition to any other access your library offers. That gives the users the most flexibility: if they need a weak_ptr, they've got immediate access to it; if they need a shared_ptr, they can easily get it; and if they just need access to the object itself, they can ignore the smart pointers entirely.

Of course, I don't know what your library does or how it's used or designed. That might change my recommendation.

征棹 2024-07-22 00:25:24

提出复杂的机制来获取图书馆的对象只会导致人们不使用您的图书馆。 如果库的语义规定你需要让人使用weak_ptrs,那么用户就无法知道这些对象可能会在某个时候消失。 让界面尽可能多地表达有关库使用的信息,减少文档记录并使其更加易于使用。

你不能围绕糟糕/缺乏经验的用户进行设计。

Coming up with convoluted mechanisms to get at the objects of your library will only result in people not using your library. If the semantics of the library dictate you need to have people using weak_ptrs, there no way around the user knowing that the objects may go away at some point. Make the interface express as much information about the usage of the library as possible, keeps documentation down and makes it infinitely easier to use.

You can't design around bad/inexperienced users.

不…忘初心 2024-07-22 00:25:24

如果您授予客户端访问 weak_ptr 的权限,他们只需锁定它们以创建 shared_ptr 并最终延迟对象的销毁。 这可能会导致您的库出现问题。

我建议将 weak_ptr 包装在其他类中,并为调用者提供一个 shared_ptr 。 这样他们就不能只调用 weak_ptr::lock()。 您似乎存在可能影响实现方式的性能限制,但 shared_ptr 可能是一个好方法,并将类保留在 weak_ptr 内部到你的图书馆。

这样,您还可以将这些实现细节保留在库接口之外,并且您可以在不更改接口的情况下更改实现方式。

If you give your clients access to weak_ptrs they can just lock them to create shared_ptrs and end up delaying the destruction of objects. That might cause problems with your library.

I suggest wrapping a weak_ptr in some other class and giving the caller a shared_ptr to that. That way they can't just call weak_ptr<T>::lock(). You seem to have performance constraints that might influence how you implement it, but a shared_ptr<InterfaceClass> might be a good way to go, and keep the class with the weak_ptr internal to your library.

That way you also keep these implementation details out of your library interface and you can change the way you implement it without changing your interface.

稳稳的幸福 2024-07-22 00:25:24

我不认为暴露weak_ptrs有任何问题,特别是考虑到 TR1 有类似的智能指针 (PDF)。

TR1 主要由 Visual Studio 和 GCC 实现,但不是其他一些编译器实现的。 但是,当它在您关心的所有编译器中实现时,您可能需要重新设计 API 以公开这些智能指针。

I don't see any problem with exposing weak_ptrs, especially given that TR1 has similar smart pointers (PDF).

TR1 is largely implemented by Visual Studio and GCC, but not some of the other compilers out there. But when it's implemented in all the compilers you care about, you may want to rework the API to expose those smart pointers instead.

情绪失控 2024-07-22 00:25:24

如果您既想捕获对库的无效使用(在删除对象时尝试访问对象)又想拥有高性能 API(API 中没有weak_ptr 和shared_ptr),那么您可以考虑使用不同的API用于调试和非调试构建。

为了简单起见,我们假设您只公开一类对象; 将该类称为对象。 然后,您从用于访问内部对象的 API 返回的指针类型定义为:

#ifdef DEBUG
typedef ObjectPtrFacade ObjectPtr 
#else
typedef Object * ObjectPtr;
#endif

这里,外观是您编写的类。 它的工作原理大致如下:

class ObjectPtrFacade {
public:
    ObjectPtrFacade(Object *o) : wptr(o) { }
    // copy constructor and assignment here etc. (not written)
    Object * operator -> () const { return access(); }
    Object & operator * () const { return *access(); }
private:
    Object * access() { 
      assert(wptr.use_count() > 0);
      return (Object *)(wptr.lock());
    }
    weak_ptr<Object> wptr; 
}

通过这种方式,每当您构建调试版本时,都会使用一种特殊的智能指针,该指针在访问对象之前断言其 use_count() 大于零,即该对象仍然存在。 如果对象已被释放,您会得到一个失败的断言,这比空指针引用要好。

一般来说,如果您有“愚蠢”的API用户,那么使用weak_ptr并没有帮助,因为他们可以调用lock(),然后在weak_ptr返回空的shared_ptr后仍然进行空指针引用。 ..

If you want to both trap invalid use of the library (trying to access the objects when they have been deleted) as well as have a high-performance API (no weak_ptr's and shared_ptr's in the API), then you could consider have a different API for debug and nondebug builds.

Let's suppose for simplicity that you have only one class of objects you expose; call this class Object. The pointer type which you return from the API for accessing the internal objects is then defined as:

#ifdef DEBUG
typedef ObjectPtrFacade ObjectPtr 
#else
typedef Object * ObjectPtr;
#endif

Here the facade is class which you write. It works roughly like this:

class ObjectPtrFacade {
public:
    ObjectPtrFacade(Object *o) : wptr(o) { }
    // copy constructor and assignment here etc. (not written)
    Object * operator -> () const { return access(); }
    Object & operator * () const { return *access(); }
private:
    Object * access() { 
      assert(wptr.use_count() > 0);
      return (Object *)(wptr.lock());
    }
    weak_ptr<Object> wptr; 
}

In this way, whenever you build a debugging build, you have a special kind of smart pointer in use which asserts before accessing the object that its use_count() is higher than zero, i.e. that the object still exists. If the object has been released, you get a failing assert, which is better than a null pointer reference.

In general of course it is so that using weak_ptr's does not help if you have "stupid" users of the API, because they could call lock() and then still make a null-pointer reference after the weak_ptr returns a shared_ptr which is empty...

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