如何克隆一个包含基类unique_ptr向量的类

3
#include <iostream>
#include <memory>
#include <vector>
#include <utility>
#include <map>

class IOutput{
public:
    virtual std::ostream& print(std::ostream& out) const = 0;
    virtual std::unique_ptr<IOutput> clone() const = 0;
    virtual ~IOutput() = default;
};

std::ostream& operator<<(std::ostream& out, const IOutput& ser) {
    ser.print(out);
    return out;
}

class String : public IOutput {
private:
    std::string m_str;
public:
    String( std::string str )
        : m_str(std::move(str))
    {}
    std::ostream& print(std::ostream& out) const override {
        out << m_str;
        return out;
    }
    std::unique_ptr<IOutput> clone() const override { return std::make_unique<String>(*this); }
};

class List : public IOutput {
private:
    std::vector<std::unique_ptr<IOutput>> m_elements;
public:
    std::ostream& print(std::ostream& out) const override {

    }
    std::unique_ptr<IOutput> clone() const override {
        return std::make_unique<List>(*this); 
    } 
};




int main () {
    String s {"string s"};
    String s2 {"string s2"};
    String s3 {"string s3"};
    String s4 {"string s4"};


    return 0;
}

错误

/usr/include/c++/7/bits/stl_construct.h:75: error: use of deleted function ‘std::unique_ptr<_Tp, _Dp>::unique_ptr(const std::unique_ptr<_Tp, _Dp>&) [with _Tp = IOutput; _Dp = std::default_delete<IOutput>]’
 { ::new(static_cast<void*>(__p)) _T1(std::forward<_Args>(__args)...); }
   ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

我发现只有在List中存在 std::vector<std::unique_ptr<IOutput>> 时才会出现这个错误。看起来在clone中调用std::make_unique<List>(*this)时,我正在复制该向量,这意味着它必须复制该向量中的每个元素,在我们的情况下(unique_ptr)是被禁止的。
如何解决?


你不能复制一个unique_ptr。请参考https://dev59.com/yGQo5IYBdhLWcg3wdPO8获取更多信息。 - Ody
1
当克隆一个独特指针的向量时,您需要显式地遍历原始向量,克隆每个元素,并将结果推送到目标向量中。 - n. m.
3个回答

6
编译器无法生成复制构造函数,因为向量成员是不可复制的。如果您希望支持复制,您需要自己实现它,例如:
List(List const& other) : m_elements(other.m_elements.size()) {
    std::transform(begin(other.m_elements), end(other.m_elements), begin(m_elements),
      [](std::unique_ptr<IOutput> const& o_ptr) {
        return o_ptr->clone();
      }
    );
}

1
一个有趣的案例,在这种情况下3/5/0法则不适用。 - François Andrieux

1

没有使用 std::transform 的替代解决方案

List(const List& other)
{
    m_elements.reserve(other.m_elements.size());
    for (const auto& x: other.m_elements) {
        m_elements.emplace_back(x->clone());
    }
}

附注:对于 xconst可选的 - 因为向量中的元素是 const,所以 x 无论是否明确声明为 const(因为是引用!)都将是 const。但这也不会有任何影响。 - Aconcagua

0

IOutput有一个clone()成员函数。你应该创建一个新的List,其中包含向量元素的克隆。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接