C++中shared_ptr和unique_ptr在资源管理方面的区别

5
我一直在考虑使用unique_ptrshared_ptr以及own_solution之间的选择。我已经排除了后者,因为我几乎肯定会做错,但是我对unique_ptrshared_ptr都有问题,因为它们都不能精确捕捉到我想要的内容。我想创建一个资源管理器,明确地拥有一个资源,但是我也想让资源管理器分发资源的引用。
如果我在资源管理器中使用unique_ptr并分发裸指针,则可能会出现逃逸(尽管这可能违反了类“合同”)。如果我使用shared_ptr并分发weak_ptr,则没有任何阻止调用者将weak_ptr转换为shared_ptr并存储,从而可能创建循环引用或更糟糕的情况,即资源存在于资源管理器的生命周期之外。所以我想要的是一个可以解除引用的weak_ptr,但不可能将其转换为shared_ptr
还是说我只是想通过代码中一些措辞强制执行协议?
感谢您对此的任何想法。

任何指针都可以像裸指针一样“逃脱”,因此我不认为这在裸指针方面有多大的缺点。 - Galik
3个回答

9
最终,你不能强迫任何人去听。在微软、苹果或任何开源库开发者那里问一下,他们都知道这首歌。一个用恰当的措辞放置在正确位置的评论是最好的选择。
避免创建自己的智能指针类,它会妨碍组合并降低可读性。作为最后的选择,尝试查找boost或代码已经使用的任何框架。
如果你有非所有者,它们可以被选为持有weak_ptr,或者(如果保证在整个过程中保持有效)使用raw pointer。
所有这些智能指针都明确表示了所有权策略。原始指针不表示任何或非所有权。
- auto_ptr:不要使用,即使对于谨慎的人也有太多陷阱。 - unique_ptr:唯一所有权。 - shared_ptr:共享所有权。 - weak_ptr:没有所有权,可能在背后被删除。 - raw pointer - 显式地没有所有权,并拥有更长的生命周期。 - 或手动所有权管理。

避免创建自己的智能指针类:C++ STD并不是万能的解决方案。如果你需要为特定应用程序编写并使用某些东西,那么就去写吧。特别是与Java或C#相比,C++是一种提供了这种自由的语言。以上仅代表个人观点。 - Danvil
@Danvil:这就是为什么只是避免使用,首选回退到常见/已经使用的框架。太多时候,用户会在第一时间回避你的智能指针类,如果它与他正在使用的其他库不匹配。他会对不得不跳过这些障碍感到不满。 - Deduplicator

6
智能指针如shared_ptr和unique_ptr是拥有指针时的好工具。
但对于非拥有指针,即观察指针,使用原始指针就可以了。
在您的设计中,我认为资源管理器是资源的唯一“所有者”,因此您可以简单地在资源管理器内部使用某种形式的智能指针。例如,资源管理器可以有一个std::vector>作为数据成员,甚至是一个更简单的std::vector,如果您的Resource类被设计为可以正确存储在std::vector中。
然后,资源管理器可以向外部提供非拥有观察指针,而原始指针(或C++引用)对于这种情况也很好。
当然,重要的是资源管理器的生命周期超过“资源客户端”的生命周期。

3
我想要的是一个可推迟的weak_ptr,它不能被转换成shared_ptr。你可以提供一个小帮助类:
template<typename T>
class NonConvertibleWeakPtr
{
public:
   NonConvertibleWeakPtr(const std::shared_ptr<T>& p) : p_(p) {}
   ... // other constructors / assignment operators
   bool expired() const { return p_.expired(); }
   T* operator->() const { return get(); }
   T& operator*() const { return *get(); }
private:
   T* get() const { return p_.lock().get(); }
private:
   std::weak_ptr<T> p_;
};

这比原始指针稍好,因为您可以检查指针是否仍然有效。
例如用法:
std::shared_ptr<int> sp = std::make_shared<int>(5);
{
    NonConvertibleWeakPtr<int> wp(sp);
    if(!wp.expired()) {
        std::cout << *wp << std::endl;
    }
}

然而,用户仍然可能滥用它,例如使用 std::shared_ptr<T> blah(&(*wp));,但这需要更多的犯罪能量。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接