我编写了一个库,它公开了对几个相关对象类型的引用。所有这些对象的生命周期都由库内部通过boost::shared_ptr
库的用户也可以根据库的性质知道任何暴露对象的生命周期。因此,他们可以存储指针或保持对这些对象的引用。他们这样做是合理的,并知道这些对象何时不再有效。
但我感到内疚,迫使我的用户合理。
让库向其对象展示weak_ptr
是否可以接受?还有其他图书馆吗?
我已经在应用程序中描述了这个库的用法,并发现它对于完全暴露weak_ptr
非常关键。
让匹配的API函数公开引用或一个weak_ptr或使任何对象能够将weak_ptr
暴露给自己会更明智吗?
答案 0 :(得分:6)
如果图书馆用户已经可以直接访问smart_ptr
,那么他们就可以通过相应的weak_ptr
构造函数访问weak_ptr
了。但是如果smart_ptr
都是库的内部,那就是另一个故事。
在这种情况下,除了您的图书馆提供的任何其他访问外,我还建议让每个对象都将weak_ptr
传递给自己。这为用户提供了最大的灵活性:如果他们需要weak_ptr
,他们可以立即访问它;如果他们需要shared_ptr
,他们可以很容易地得到它;如果他们只需要访问对象本身,他们可以完全忽略智能指针。
当然,我不知道你的图书馆做了什么,或者它是如何使用或设计的。这可能会改变我的建议。
答案 1 :(得分:4)
使用复杂的机制来获取图书馆的对象只会导致人们不使用您的图书馆。如果库的语义决定你需要让人们使用weak_ptrs,那么用户就无法知道对象可能会在某些时候消失。使界面尽可能多地表达有关库使用的信息,保持文档记录并使其更容易使用。
你不能围绕坏/没有经验的用户进行设计。
答案 2 :(得分:2)
如果您让客户访问weak_ptr
,他们可以锁定它们以创建shared_ptr
并最终延迟对象的销毁。这可能会导致您的库出现问题。
我建议在其他课程中包含weak_ptr
,然后向调用者提供shared_ptr
。这样他们就不能只召唤weak_ptr<T>::lock()
。您似乎有可能影响实现方式的性能限制,但shared_ptr<InterfaceClass>
可能是一个很好的方法,并保持类库内部weak_ptr
。
通过这种方式,您还可以将这些实现细节保留在库接口之外,并且可以在不更改界面的情况下更改实现方式。
答案 3 :(得分:1)
我没有看到暴露weak_ptrs有任何问题,特别是考虑到TR1 has similar smart pointers(PDF)。
TR1主要由Visual Studio和GCC实现,但不是其他一些编译器。但是当它在您关心的所有编译器中实现时,您可能需要重新编写API以显示这些智能指针。
答案 4 :(得分:0)
如果你想同时捕获库的无效使用(尝试在删除对象时访问它们)以及拥有高性能API(API中没有weak_ptr和shared_ptr),那么你可以考虑用于调试和非调试构建的不同API。
为简单起见,我们假设您只公开了一类对象;称这个类为Object。然后,从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之后仍然做一个空指针引用是空的......