2015-03-18 5 views
5

Мне нужно написать конструктор копирования, который также передает право собственности на экземпляр unique_ptr копируемого объекта. Ситуация выглядит следующим образом:Копировать конструктор для передачи права собственности на unique_ptr

class C{ 
    // C class stuff  
}; 

class A{ 
public: 
    public A(); 
    public A(const A& a); 
private: 
    std::unique_ptr<C> c_; 
} 

class B{ 

public: 

    B(const A& b) : a_(a){} 

private: 
    A a_; 


}; 

Как я должен реализовать конструктор копирования для A?

+10

Итак, когда вы делаете копию, вы хотите сделать оригинал недействительным? Я бы предложил удалить конструктор копирования и сделать класс только движимым. – NathanOliver

+0

Если с оригиналом вы имеете в виду исходный объект A, да, он должен быть «transferref» в качестве члена класса B. Можете ли вы привести пример этого? – gcswoosh

+3

@Gabrielecswoosh Проведите некоторое время, прочитав вопросы/ответы по тегу [tag: move-semantics]. –

ответ

5

Ваши намерения или подход ошибочны, я думаю.

Контент-конструктор предназначен для создания копии аргумента, но поскольку unique_ptr не имеет права собственности, копировать его невозможно. Вы могли бы на самом деле сделать unique_ptr member mutable, а затем переместить ресурс, на который указывает он в copy-constructor, но это было бы абсолютно безумным (это то, что делает std::auto_ptr, и именно поэтому оно устарело).

Поэтому либо вам нужно:

  • добавить перемещение-конструктор в А и В (+ сделать копию-конструктор удален)
  • переход от unique_ptr к shared_ptr, но только если C на самом деле предназначены для совместно

Там также третий вариант, который должен сделать копию объекта, на который указывает unique_ptr в копии-конструктор, то есть:

A::A(const A& a) : c_(std::unique_ptr<C>(a.c_ ? new C(*a.c_) : nullptr)) { 
} 
+0

Я бы не назвал намерение неправильным. Совершенно прекрасно создавать интерфейс, моделирующий * обычный тип *, который не может выставляться в обернутом виде. – mavam

+0

Я не согласен с тобой. вы можете скопировать объект, который содержит unique_ptr. например, я мог бы реализовать класс LinkedList, который содержит unique_ptr как указатель для следующего элемента. означает ли это, что я не могу или не должен копировать любимый список? Возможно, мне захочется скопировать связанный список и сохранить эту копию в unique_ptr скопированного объекта –

+4

@DavidHaim, но OP хочет передать право собственности в copy-constructor - это то, о чем говорится в названии вопроса. Я считаю это неправильным подходом. –

3

Технически, чтобы

написать копирующий конструктор, который также передать право собственности на unique_ptr члена объекта скопированный

вы можете просто сделать это:

class Bad 
{ 
private: 
    unique_ptr<int> p_; 
public: 
    Bad(): p_(new int(666)) {} 
    Bad(Bad& other) 
     : p_(move(other.p_)) 
    {} 
}; 

Поскольку конструктор копирования может иметь также эту подпись, plu s еще два, в дополнение к более обычным Bad(const Bad&).

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

Вместо конструктора копирования, не копировать,

  • реализовать конструктор перемещение, движется или

  • осуществить обычный конструктор копирования, копии или

  • изменить класс, например, на дом совместного пользования.

4

Очевидно, что вы не можете просто сделать уступку std::unique_ptr с, как их оператор присваивания удаляется. Это преднамеренно заставить программиста определить поведение, которое он хочет.

  1. Новый предмет принадлежит c_, недействительный оригинал.
  2. Новый товар делает копию c_, сохраняя при этом подлинность оригинала.
  3. Новый элемент владеет долей c_, так что и новые, и оригинальные элементы ссылаются на один и тот же объект.

В случае 1 то, что вы ищете, является шагом конструктор и конструктор двигаться по умолчанию будет работать нормально. Так что вам не нужно писать код, вы можете просто сделать:

A temp; 
A foo(std::move(temp)); 

Обратите внимание, что temp является недействительным после его перемещения.

В случае 2 вам нужно добавить конструктор пользовательских копий в A создать копию оригинала c_:

A(const A& a):c_(new C(*(a.c_))){} 

После определения этого в A вы можете сделать:

A foo(A()); 

Обратите внимание, что это зависит от конструктора копии C, являющегося функциональным.

В случае 3 вам необходимо коренным образом изменить A с помощью std::unique_ptr с помощью std::shared_ptr, поэтому определение c_ стало бы:

std::shared_ptr<C> c_; 

Ваше строительство c_ будет идентичен что вы уже используете для версии std::unique_ptr версии c_. Таким образом, только с помощью реализации по умолчанию вы можете сделать:

A foo; 
A bar(foo); 

А теперь foo и bar указывают на то же C объекта и долевой собственности его. Этот общий объект не будет удален до тех пор, пока все ссылки shared_ptr s не будут удалены.

Смежные вопросы