Как реализовать функцию глубокого копирования в каком-нибудь интеллектуальном указателе?

#c #smart-pointers

#c #интеллектуальные указатели

Вопрос:

unique_ptr весьма полезен. Однако он не может быть скопирован. Если для его указанного класса будут предоставлены методы вирусного клонирования (глубокого копирования), я думаю, это станет более полезным. Необходимо ли это или какой-либо лучший способ его реализации? Любой подобный интеллектуальный указатель существует в какой-либо библиотеке? Вот версия

 template<class T>
class deep_ptr: private unique_ptr<T>
{
public:
    using unique_ptr<T>::operator *;
    using unique_ptr<T>::operator ->;
    using unique_ptr<T>::operator bool;
    using unique_ptr<T>::release;
    using unique_ptr<T>::reset;
    using unique_ptr<T>::get;

    // add (DEFAULT_CONSTRUCTOR)(MOVE_CONSTRUCTOR)(MOVE_ASSIGNMENT_METHOD) ...

    explicit deep_ptr(T* p) : unique_ptr(p) {}

    deep_ptr(deep_ptr constamp; r) : unique_ptr(r->clone()) {}

    deep_ptramp; operator=(deep_ptrconstamp; r)
    { if (this != amp;r) reset(r->clone()); return *this; }
};
 

Я чувствую, что это очень полезно, но никогда не вижу подобных вещей. ???

Комментарии:

1. Можете ли вы опубликовать несколько строк кода, чтобы указать, как вы собираетесь его использовать?

2. @GuyGreer О, мой плохой, я неправильно истолковал вопрос.

3. @GuyGreer — shared_ptr не имеет ни глубокой, ни мелкой семантики копирования. Это зависит от объекта, на который он указывает

4. @EdHeal Я имел в виду, что копирование shared_ptr не копирует базовый объект, что делает его мелкой копией, если я чего-то не понимаю.

5. «… Однако он не может быть скопирован» — создание возможности копирования создало бы ситуацию, когда два unique_ptr объекта управляют одним и тем же объектом. Это нарушило бы семантику единого владения unique_ptr .

Ответ №1:

Если я не понимаю, что вы ищете, если у класса есть метод clone, этого должно быть достаточно, чтобы получить то, что вы ищете.

Пример кода:

 #include <iostream>
#include <memory>

struct A
{
   virtual ~A() {}
   virtual A* clone() = 0;
};

struct B : A
{
   B(int in = 0) : x(in) {}
   B(B constamp; copy) : x(copy.x) {}
   virtual ~B() {std::cout << "In B::~B()n";}

   virtual A* clone() { return new B(*this); }
   int x;
};

int main()
{
   std::unique_ptr<A> p1(new B(10));
   std::unique_ptr<A> p2(p1->clone());
   return 0;
}
 

Результат выполнения вышеуказанной программы:

В B::~B()
В B::~B()

Комментарии:

1. Если указатель является членом класса, который можно копировать глубоко. Я не могу использовать конструктор неявного копирования.

2. @user1899020, вы имеете в виду «если std::unique_ptr является членом класса …»??

3. например, класс A { unique_ptr<B> mB; … } и чтобы сделать копируемый, нам нужно написать конструктор копирования. При использовании deep_ptr мы можем использовать версию, предоставляемую компилятором.

4. @user1899020, если у вас нет большого количества таких классов, лучше написать конструктор копирования для A , чем для производного std::unique_ptr .

Ответ №2:

Без метода clone (просто конструктора копирования) должно работать следующее:

 template <typename T>
class deep_ptr
{
public:
  deep_ptr() : i_() {}

  deep_ptr(std::nullptr_t) : i_(nullptr) {}

  template <typename U>
    deep_ptr(U* u) : i_(u ? new inner_impl<U>(*u) : nullptr) {}

  ~deep_ptr() { delete i_; }

  deep_ptr(const deep_ptramp; p) : i_(p.i_ ? p.i_->copy() : nullptr) {}

  deep_ptramp; operator=(const deep_ptramp; p)
  {
    if (!p.i_) { i_ = nullptr; }
    else { i_ = p.i_->copy(); }
  }

  deep_ptr(deep_ptramp;amp; p) : i_(p.i_) { p.i_ = nullptr; }

  deep_ptramp; operator=(deep_ptramp;amp; p)
  {
    i_ = p.i_;
    p.i_ = nullptr;
  }

  const T* operator->() const { return get(); }

  const T* get() const
  {
    if (i_) { return *i_; }
    return nullptr;
  }

  const Tamp; operator*() const { return *static_cast<T*>(*i_); }

  T* operator->() { return get(); }

  T* get()
  {
    if (i_) { return *i_; }
    return nullptr;
  }

  Tamp; operator*(){ return *static_cast<T*>(*i_); }

private:
  struct inner
  { 
    virtual inner* copy() const = 0;
    virtual operator const T*() const  = 0;
    virtual operator T*() = 0;
    virtual ~inner() {}
  };

  inner* i_;

  template <typename U>
  struct inner_impl : inner
  {
    inner_impl(const Uamp; u) : u_(u) {}
    inner_impl* copy() const override { return new inner_impl(u_); }
    operator const T*() const override { return amp;u_; }
    operator T*() override { return amp;u_; }

    U u_;
  };
};