Как / возможно ли иметь вектор & lt; unique_ptr & lt; ABC & gt; & gt ;?

Обновление старого кода, в котором я вручную обрабатывал время жизни вектора необработанных указателей до конкретных экземпляров абстрактного базового класса (ABC).

Таким образом, у владельца вектора был виртуальный dtor, который вручную просматривал и удалял содержимое вектора и т. Д.

Поскольку владелец вектора владеет элементами в нем, имеет смысл изменить это на вектор unique_ptr.

К сожалению, кажется, это невозможно? Потому что vector<unique_ptr<type>> должен быть в состоянии иметь статический дтор для type но поскольку в данном случае тип является ABC, он недоступен, поэтому vector не скомпилируется …

Или я что-то упустил?

например.:

struct ABC
{
ABC() = default;
virtual ~ABC() { } // need a vtable entry so that concrete subclasses will be deleted through the base dtor

virtual std::unique_ptr<ABC> Clone() = 0;
virtual void Foo() = 0;

std::vector<std::unique_ptr<ABC>>   elements;
};

EDIT2: вот полный пример, который терпит неудачу:

#include <iostream>
#include <memory>
#include <vector>

struct ABC
{
virtual ~ABC() { } // need a vtable entry so that concrete subclasses will be deleted through the base dtor

virtual std::unique_ptr<ABC> Clone() = 0;
virtual void Foo() = 0;

std::vector<std::unique_ptr<ABC>>   elements;
};

struct Child : ABC
{
std::unique_ptr<ABC> Clone() override { return std::make_unique<Child>(*this); }
void Foo() override { };
};

struct Derived : Child
{
std::unique_ptr<ABC> Clone() override { return std::make_unique<Derived>(*this); }
};

int main()
{
std::unique_ptr<ABC> x;
std::unique_ptr<ABC> c = std::make_unique<Child>();

std::vector<std::unique_ptr<ABC>>   elements;
elements.emplace_back(std::make_unique<Derived>());
return 0;
}

1

Решение

Ошибка возникает при попытке скопировать экземпляр Base или экземпляр типа, производного от Base, Конструктор копирования по умолчанию попытается скопировать Base::elements, который пытается скопировать каждый из его элементов в новый vector, Поскольку эти элементы unique_ptr<Base> эта копия не разрешена.

Этот пример воспроизводит проблему:

#include <memory>
#include <vector>

struct Base
{
using PBase = std::unique_ptr<Base>;
using VBase = std::vector<PBase>;

VBase   elements;
};

int main()
{
Base x;
auto y = x; // This line causes the error

return 0;
}

Скорее всего, вам потребуется реализовать собственный конструктор копирования и оператор копирования или запретить копирование, удалив эти функции. С помощью shared_ptr вместо этого может работать, если мелкие копии будут работать для вашего приложения.

4

Другие решения

Для полноты картины вот что я должен был сделать:

class ABC
{
public:
ABC() = default;
ABC(const ABC & rhs)
{
// manually clone our elements
elements.reserve(rhs.elements.size());
for (const auto & e : rhs.elements)
elements.emplace_back(e->Clone());
}
ABC & operator = (const ABC &) = delete;

virtual ~ABC() { } // need a vtable entry so that concrete subclasses will be deleted through the base dtor

virtual std::unique_ptr<ABC> Clone() = 0;
virtual void Foo() = 0;

std::vector<std::unique_ptr<ABC>>   elements;
};
0