【问题标题】:How / Is it possible to have a vector<unique_ptr<ABC>>?如何/是否有可能有一个向量<unique_ptr<ABC>>?
【发布时间】:2023-03-29 01:11:01
【问题描述】:

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

所以向量的所有者有一个虚拟的dtor,它手动遍历并删除了向量的内容等。

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

可悲的是,这似乎是不可能的?因为vector&lt;unique_ptr&lt;type&gt;&gt; 必须能够拥有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;
}

【问题讨论】:

  • 不确定其他所有人,但如果您在问题的示例代码中使用相同的名称,它会使您的要求更加清晰。也就是说,你得到的错误是什么?您的示例代码为我编译。
  • 你不能直接转发声明Base吗?就在你定义它之前?
  • 我从 VS 2015 Upd 3 收到一英里长的消息,这基本上是由于 Base 中的删除 ctor 而无法实例化向量的默认填充 elements(大概是因为它是ABC)
  • 很奇怪。当我运行 this 时,我在我的 MSVS 2015 版本上没有任何问题。我也在更新 3。请提供给出这些错误的 minimal reproducible example
  • 啊,我明白了,这是Clone() 函数——他们明确地试图复制基础中的元素。哦!谢谢!

标签: c++ vector unique-ptr abc


【解决方案1】:

当您尝试复制Base 的实例或从Base 派生的类型的实例时会发生错误。默认的复制构造函数将尝试复制Base::elements,它尝试将它的每个元素复制到新的vector 中。由于这些元素是unique_ptr&lt;Base&gt;,因此不允许复制。

这个例子重现了这个问题:

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

【讨论】:

  • 谢谢。我只是没有看到明显的。非常感谢。
【解决方案2】:

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

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

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2021-06-14
    • 2014-03-26
    • 2011-05-07
    • 2011-06-06
    • 1970-01-01
    • 2019-01-27
    • 2014-11-09
    • 2012-08-14
    相关资源
    最近更新 更多