Передать вектор C ++ для unique_ptr <T>без передачи права собственности - PullRequest
1 голос
/ 26 июня 2019

У меня есть класс 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 для использования (не вступать во владение)?

Ответы [ 2 ]

3 голосов
/ 26 июня 2019

Вы не можете иметь два std::unique_ptr, указывающих на один и тот же объект.unique_ptr подразумевает уникальное владение.

Если вам нужно разделить владение, используйте вместо него std::shared_ptr s.В вашем примере это должна быть вставная замена, просто измените объявление 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;
};

Конечно, это будет означать, что вы рискуете оставить элементы _vec висящими, если Outerосвобождает любой из Element s, которыми он владеет, без обновления каких-либо Inner объектов, указывающих на них.Вы могли бы частично уменьшить этот риск, сохранив указатель на объект Outer вместо хранения указателей непосредственно на Element s:

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

    //...
};

class Inner
{
    // ...

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

private:
    Outer* outer_;
};

Inner только тогда получит доступ к его Element s черезобъект Outer (при необходимости вы можете сделать Inner a friend из Outer).Это все еще оставляет возможность того, что объект Inner может пережить объект Outer, на который он указывает, но это несколько снижает риск.

1 голос
/ 26 июня 2019

Если 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
};
...