【问题标题】:Pass C++ vector of unique_ptr<T> without passing ownership传递 unique_ptr<T> 的 C++ 向量而不传递所有权
【发布时间】:2019-11-08 19:19:46
【问题描述】:

我有一个 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 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(),因为否则编译器会抱怨我试图在每个向量元素上调用一个已删除的函数(可能是复制构造函数)。

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

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

【问题讨论】:

  • std::unique_ptr 不能以任何方式复制。如果它被移动,则所有权被传递。请改用 shared_ptr。
  • Inner 可以在外层而不是它自己的副本中存储指向向量的引用或(原始)指针。 (假设所有 Inner 实例都归 Outer 所有,这似乎没有风险。当然,要小心复制 Outer 对象...

标签: c++ c++11 move smart-pointers unique-ptr


【解决方案1】:

你不能有两个std::unique_ptrs 指向同一个对象。 unique_ptr 表示唯一所有权。

如果您需要共享所有权,请改用std::shared_ptrs。在您的示例中,它应该是一个直接替换,只需更改 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 释放了它拥有的任何Elements 而没有更新任何指向它们的Inner 对象,那么这样做意味着你冒着让_vec 的元素悬空的风险.您可以通过存储指向 Outer 对象的指针而不是直接存储指向 Elements 的指针来部分减轻这种风险:

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

    //...
};

class Inner
{
    // ...

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

private:
    Outer* outer_;
};

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

【讨论】:

    【解决方案2】:

    如果 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
    };
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2020-12-23
      • 1970-01-01
      • 2016-03-18
      • 2017-08-31
      • 1970-01-01
      • 1970-01-01
      • 2020-07-14
      相关资源
      最近更新 更多