【问题标题】:Deep Clone for a unique_ptr which point to a base class指向基类的 unique_ptr 的深度克隆
【发布时间】:2017-02-22 08:30:20
【问题描述】:

问题是:如何对指向基类的 unique_ptr 进行深度克隆,并且基类具有一些虚函数。

详细代码:

class QueryRewrite {
public:
     QueryRewrite(bool wasRes, ReturnMeta rmeta, const KillZone &kill_zone, 
                  AbstractQueryExecutor *const executor)
         : rmeta(rmeta), kill_zone(kill_zone),
           executor(std::unique_ptr<AbstractQueryExecutor>(executor)) {}
     QueryRewrite(const QueryRewrite &other_qr)
         : rmeta(other_qr.rmeta), kill_zone(other_qr.kill_zone),
           executor(other_qr.executor.get()) {}
     QueryRewrite(){}
     QueryRewrite(QueryRewrite &&other_qr) : rmeta(other_qr.rmeta),
           executor(std::move(other_qr.executor)) {}
     const ReturnMeta rmeta;
     const KillZone kill_zone;
     std::unique_ptr<AbstractQueryExecutor> executor;
};

在复制构造函数中

QueryRewrite(const QueryRewrite &other_qr)
         : rmeta(other_qr.rmeta), kill_zone(other_qr.kill_zone),
           executor(other_qr.executor.get()) {}

executor(other_qr.executor.get())只是对执行器的浅拷贝,如果我想做深拷贝,代码怎么改?

executor 是一个unique_ptr,它指向AbstractQueryExecutor 的一个实例,AbstractQueryExecutor 是一个具有一些虚函数的基类,所以如果我将代码更改为 executor(new AbstractQueryExecutor(other_qr.executor.get())),它会说:

 error: cannot allocate an object of abstract type ‘AbstractQueryExecutor’
 note:   because the following virtual functions are pure within ‘AbstractQueryExecutor’:

【问题讨论】:

  • C 介绍了unique_ptr 以及使它们工作所需的所有基础!?酷!
  • unique_ptr 与问题没有真正的关系。这是多态复制的经典问题,通常由一个虚拟的clone() 成员函数来解决。
  • executor(other_qr.executor.get()) 不是浅拷贝,它创建了一个指针,两个不同的unique_ptrs 都认为他们唯一拥有。这不好。

标签: c++ constructor abstract-class unique-ptr


【解决方案1】:

编写一个继承自unique_ptrvalue_ptr,但在复制构造/分配时会在非空T* 上调用unique_ptr&lt;T&gt; T::clone() const 以进行克隆。

使用那个。

template<class T, class D=std::default_delete<T>>
struct value_ptr:std::unique_ptr<T,D>{
  using base=std::unique_ptr<T,D>;
  using base::base;
  value_ptr()=default;
  value_ptr(value_ptr&&)=default;
  value_ptr& operator=(value_ptr&&)=default;
  value_ptr(base&& o):base(std::move(o)){}
  value_ptr(value_ptr const&o):
    value_ptr( o?value_ptr(o->clone()):value_ptr() )
  {}
  value_ptr& operator=(value_ptr const&o){
    value_ptr tmp(o);
    *this=std::move(tmp);
    return *this;
  }
};

应该这样做。代码未测试。

抽象基础需要添加一个virtual std::unique_ptr&lt;AbstractBase&gt; clone()const,并且派生需要实现,才能使上述工作。

也遵循零规则;一旦你有一个值 ptr,你可以=default 或者有时跳过封闭类的复制/移动 ctors/assigns。

顺便说一句,请考虑写入时复制而不是深度复制。

【讨论】:

    猜你喜欢
    • 2019-05-14
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-08-13
    • 2010-10-25
    • 2012-01-05
    • 2023-04-03
    • 2017-02-23
    相关资源
    最近更新 更多