如何/是否可以有一个向量<unique_ptr<ABC>>?

问题描述 投票:0回答:2

修改一些旧代码,在这些代码中我手动处理指向抽象基类 (ABC) 的具体实例的原始指针向量的生命周期。

因此向量的所有者有一个虚拟 dtor,它手动检查并删除向量的内容等。

由于向量的所有者拥有其中的元素,因此将其更改为 unique_ptr 的向量很有意义。

可悲的是,这似乎是不可能的?因为

vector<unique_ptr<type>>
必须能够拥有
type
的静态 dtor,但因为在这种情况下类型是 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;
}
c++ vector unique-ptr abstract-base-class
2个回答
4
投票

当您尝试复制

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
可能会起作用。


0
投票

为了完整起见,这是我应该做的:

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;
};
© www.soinside.com 2019 - 2024. All rights reserved.