0

The problem is: How can I do the deep clone for a unique_ptr which point to a base class, and the base class has some virtual functions.

The detail code:

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

In the copy constructor

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()) is just a shallow copy to the executor, if I want to do the deep copy, how to change the code?

And executor is a unique_ptr which point to an instance of AbstractQueryExecutor, the AbstractQueryExecutor is a base class which has some virtual functions, so if I change the code to executor(new AbstractQueryExecutor(other_qr.executor.get())), it will say something like:

 error: cannot allocate an object of abstract type ‘AbstractQueryExecutor’
 note:   because the following virtual functions are pure within ‘AbstractQueryExecutor’:
unwind
  • 391,730
  • 64
  • 469
  • 606
user2655973
  • 315
  • 3
  • 13

1 Answers1

0

Write a value_ptr which inherits from a unique_ptr, but on copy construct/assigning invokes unique_ptr<T> T::clone() const on non-null T* to clone.

The use that.

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

That should do it. Code not tested.

The abstract base needs to have a virtual std::unique_ptr<AbstractBase> clone()const added, and derived need to implement, for the above to work.

Also follow the rule of zero; once you have a value ptr, you can =default or sometimes skip the copy/move ctors/assigns of enclosing classes.

As an aside, consider copy on write instead of deep copy.

Yakk - Adam Nevraumont
  • 262,606
  • 27
  • 330
  • 524