class 存储对 unique_ptr 的引用的 best/most 直观方法是什么?

What is the best/most intuitive way for a class to store a reference to a unique_ptr?

我有一个 class 来管理 unique_ptrs 的向量:

class Foo
{
public:
...
private:
    std::vector<std::unique_ptr<SomeClass>> vec_;
};

我有另一个 class,Bar,我想存储一些引用向量中的对象的引用类型。实现这一目标的最合乎逻辑和最直观的方法是什么?

我能想到的有四种:

Bar 存储引用

struct Bar
{
    Bar(std::unique_ptr<SomeClass>& ref) : ref_(ref) {}
    std::unique_ptr<SomeClass>& ref_;
};

这很简单,但是如果不重新构造对象就无法重置引用。这仍然是首选方法吗?

FooBar

中都使用 shared_ptr
class Foo
{
public:
...
private:
    std::vector<std::shared_ptr<SomeClass>> vec_;
};

struct Bar
{
    std::shared_ptr<SomeClass> ref_;
};

这个问题是它暗示 FooBar 对对象具有平等的所有权,即使 Foo 应该拥有所有权。但也许这没什么大不了的?我犹豫的原因是我读过,如果所有权确实相等,你应该只使用 shared_ptr 。我也知道 shared_ptrunique_ptr.

相比有相当多的开销

使用weak_ptr表明Bar没有对象的所有权(但是,迫使你仍然在Foo中使用shared_ptr

struct Bar
{
    std::weak_ptr<SomeClass> ref_;
};

对我来说,这似乎是一种干净利落的方法。我能看到的唯一缺陷是我们必须在 Foo 中使用 shared_ptr,即使 Foo 拥有唯一所有权。

使用unique_ptr::get获取Bar存储

的原始指针
struct Bar
{
    SomeClass* ref_;
}

这是我最不喜欢的选项。我们使用智能指针的全部原因是为了避免使用原始指针。将它们用于像引用智能指针这样简单的事情感觉很愚蠢。

在考虑性能和代码可维护性时,这些选项中的哪一个是首选,或者它是主观的?

The whole reason we use smart pointers is to avoid having to work with raw pointers

不:我们使用智能指针的全部原因是为了避免必须使用 拥有 原始指针。

参考 C++ Core Guidelines:

R.3: A raw pointer (a T*) is non-owning

我们确实更喜欢智能指针来拥有资源。但是,它不拥有资源,因此使用原始指针没问题。

您的备选方案从最差到最好:

  1. Bar 存储了一个参考:如果您想要重新安装它,请不要使用参考。你说你确实想要重新安装它,所以这已经结束了。尝试解决这个问题没有任何好处,它只会让您的代码更令人惊讶,而不是更好。

  2. 在两个地方都使用 shared_ptr:如果您需要对象在存在引用的情况下保持活动状态,请执行此操作。

    不要担心“平等所有权”,担心语义是否对你的程序有意义。你的工作是决定在Foo::vec_中重置指针是否应该销毁对象,而不是在C++中表达共产主义宣言。

  3. 使用shared_ptrweak_ptr:如果要Bar检测到对象已经被销毁

    优点是它很好地记录了关系,您不必担心在更新 FooBar 之间意外访问悬空指针。

拥有一个非拥有的原始指针非常好,只要您确信一旦它不再有效就不会意外取消引用。 话虽如此,shared_ptr 的开销主要出现在构造函数和析构函数调用期间(+使用内存中的一些小开销,因为需要为每个通过 shared_ptr 拥有的对象分配一个额外的控制块),因此,只要您不关心内存的每个字节并且不在任何地方按值传递 shared_ptrs,您就不太可能注意到任何显着的性能差异 - 因此具有 shared_ptr拥有该对象和用于存储引用的 weak_ptr 可能是一种更安全、更好的方法。