C++ 的shared_ptr 对比unique_ptr用于资源管理
-
21-12-2019 - |
题
我一直在考虑使用 unique_ptr
与 shared_ptr
与 own_solution
. 。我对后者不以为然,因为我几乎肯定会弄错,但我对两者都有问题 unique_ptr
和 shared_ptr
因为两者都没有准确地捕捉到我想要的东西。我想创建一个明确拥有资源的资源管理器,但是我希望资源管理器也分发对该资源的引用。
如果我使用 unique_ptr
在资源管理器中并分发原始指针,它们有可能逃逸到其他地方(尽管这违反了我认为的类“合同”)。如果我使用 shared_ptr
并分发 weak_ptr
, ,没有什么可以阻止调用者转换 weak_ptr
到一个 shared_ptr
并存储它,从而可能创建一个循环,或更糟糕的是,资源的生命周期超出了资源管理器的生命周期。所以我想我正在寻找的是一个可尊敬的 weak_ptr
无法转换为 shared_ptr
.
或者我只是想通过代码中一些措辞强硬的注释来执行合同?
感谢您对此可能有的任何想法。
解决方案
智能指针如 shared_ptr
和 unique_ptr
当你拥有时是一个很好的工具 拥有 指针。
但对于非拥有指针,即 观察指针, ,使用原始指针就可以了。
在您的设计中,我认为资源管理器是资源的唯一“所有者”,因此您可以简单地拥有某种形式的智能指针 里面 资源管理器。例如,资源管理器可以有一个 std::vector<std::unique_ptr<Resource>>
作为数据成员,甚至更简单 std::vector<Resource>
如果你的 Resource
类被设计为可以正确存储在 std::vector
.
然后,资源管理器可以向外部提供非拥有的观察指针,并且原始指针(或 C++ 引用)适合这种情况。
当然,重要的是资源管理器的生命周期要超过“资源客户端”的生命周期。
其他提示
最后,你不能强迫任何人听。询问微软、苹果或任何开源库开发人员,他们都知道这首歌。在正确的词语和位置发表评论是您最好的选择。
避免创建自己的智能指针类,它会阻碍组合并降低可读性。作为最后的手段,尝试查看 boost 或您的代码已经可以使用的任何框架。
如果您有非所有者,他们可以选择持有 weak_ptr
s 或(如果保证在持续时间内保持有效)原始指针。
如果你使用 shared_ptr
内部(为什么要),最好提供 weak_ptr
和原始指针。
所有这些智能指针都明确表示所有权策略。原始指针表示无或不拥有。
auto_ptr
:不要使用,即使对于谨慎的人来说,也不推荐使用,因为有太多陷阱。unique_ptr
:独家所有权。shared_ptr
:共享所有权weak_ptr
:没有所有权,可能会被你背后删除。- 原始指针
- 明确无所有权,保证更长的使用寿命
- 或手动所有权管理。
因此,我想我正在寻找的是一个可推迟的feek_ptr,无法转换为共享_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));
, ,不过需要多一点犯罪能量。