传递 unique_ptr<T> 的 C++ 向量而不传递所有权

Pass C++ vector of unique_ptr<T> without passing ownership

我有一个 class Outer,其中包含一个 Inner 成员和 拥有 一个 unique_ptr 元素的向量:

using Elements = std::vector<std::unique_ptr<Element>>;

class Outer
{
    void call()
    {
        _inner.aMethod(_vec);
    }

    Inner _inner;
    Elements _vec;   // This should remain the owner of each Element
};

Inner 接收 unique_ptr 个元素的向量,并将所有权转移到它自己的向量 class 成员:

class Inner
{
    public:
    Inner() = default;
    ~Inner() = default;

    void aMethod(Elements& vec)
    {
        _vec = std::move(vec);
    }

    private:

    Elements _vec;  // This is a vector of unique_ptr but I don't want this class to own the memory
};

我愚蠢地使用了 std::move(),否则编译器会抱怨我试图在每个向量元素上调用已删除的函数(可能是复制构造函数)。

我有一个非法的内存访问,我相信这是因为两个 class 都认为他们拥有矢量元素并且一个试图删除一个已经删除的 Element.

如何让 Outer 拥有内存并将元素传递给 Inner 使用(不取得所有权)?

如果 Inner 应该访问相同的向量但不拥有它,为什么不让 Inner 保留对 Outer 中的向量的引用,因为它们具有相同的生命周期?

class Inner
{
    public:
    Inner(Elements& vec):_vec(vec) {}
    ~Inner() = default;

    private:

    Elements& _vec;  // This is a reference to vector of unique_ptr, no ownership
};

不能有两个 std::unique_ptr 指向同一个对象。 unique_ptr 意味着 唯一 所有权。

如果您需要共享所有权,请改用 std::shared_ptrs。在您的示例中,它应该是 drop-in 替换,只需更改 using 声明:

using Elements = std::vector<std::shared_ptr<Element>>;

如果您不希望 Inner 对象拥有其 _vec 成员指向的对象,那么它应该是原始指针的向量:

class Outer
{
    void call()
    {
        std::vector<Element*> observer;
        std::transform(_vec.begin(), _vec.end(), std::back_inserter(observer),
                       [](std::unique_ptr<Element>& el) { return el.get(); });
        _inner.aMethod(observer);
    }

    //...
};

class Inner
{
    // ...

    void aMethod(std::vector<Element*> vec)
    {
        _vec = std::move(vec);
    }

private:
    std::vector<Element*> _vec;
};

当然,这样做意味着如果 Outer 释放它拥有的任何 Element 元素,那么您 运行 将面临让 _vec 的元素悬空的风险不更新任何指向它们的 Inner 对象。您可以通过存储指向 Outer 对象的指针而不是直接存储指向 Element 对象的指针来部分减轻这种风险:

class Outer
{
    void call()
    {
        _inner.aMethod(this);
    }

    //...
};

class Inner
{
    // ...

    void aMethod(Outer* outer)
    {
        outer_ = outer;
    }

private:
    Outer* outer_;
};

Inner 将仅通过 Outer 对象访问其 Element(您可以使 Inner 成为 Outerfriend如有必要)。这仍然存在 Inner 对象可能比它指向的 Outer 对象更长寿的可能性,但它确实在一定程度上降低了风险。