2016-10-13 3 views
1

Я пытаюсь реализовать конструктор копирования и оператор присваивания для класса. Я немного путаюсь с идиомой обмена копиями. Особенно, когда речь идет о конструкторе копирования. Является ли идентификатор обмена копиями каким-либо образом с конструктором копирования? Как избежать дублирования кода?Как реализовать конструктор копирования для id_om copy swap

Вот мой класс

Заголовок:

Class Actor 
{ 
public: 
    Foo* foo; 
    Bar bar; 
    double member1; 
    bool member2; 
    unsigned int member3; 

    void Swap(Actor& first, Actor& second); 
    Actor(const Actor&); 
    Actor& operator=(const Actor); 
} 

Cpp:

void Actor::Swap(Actor& first, Actor& second) 
{ 
    // Swap wont work with my non pointer class 
    Bar temp = first.bar; 
    first.bar = second.bar; 
    second.bar = temp; 

    std::swap(first.foo, second.foo); 
    std::swap(first.member2, second.member2); 
    std::swap(first.member3, second.member3); 
} 

// What goes here? Is this a correct copy constructor? Does this have anything to do with a copy swap idiom? How can I avoid code duplication in my copy constructor? 
Actor::Actor(const Actor& other) 
{ 
    foo = new Foo(); 
    *foo = *other.foo; 

    bar = other.bar; 
    member1 = other.member1; 
    member2 = other.member2; 
    member3 = other.member3; 
} 

Actor& Actor::operator=(Actor other) 
{ 
    Swap(*this, other); 
    return *this; 
} 

Я после этого руководства: What is the copy-and-swap idiom?

+0

Что такое 'Record :: Actor'? Ничего другого не квалифицирует «Запись ::' – StoryTeller

+0

Это была опечатка. – marsh

+2

Помимо объявления 'Swap' как нестатической функции-члена (вместо функции друга или, по крайней мере, статической функции-члена), идиома кажется примененной правильно. Вы написали копию и свопинг и получили бесплатное задание (обратите внимание, что он вызывает конструктор копирования неявно, получив свой аргумент по значению). Другой совет: называть его 'swap' вместо' Swap' и использовать 'using std :: swap; swap (x, y); 'вместо' std :: swap (x, y) 'включает ADL, что полезно для пользовательских типов. –

ответ

5

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

Искренне, основная мотивация для копирования и замены (CAS) заключается не в том, чтобы избегать дублирования кода, а в большей степени о предоставлении надежной гарантии исключения. Это означает, что если вы попытаетесь выполнить назначение копии и не получится, то объект, который вы пытались назначить, каким-либо образом не изменен. Вообще говоря, перемещение конструкции/присваивания не выбрасывается, и копирование конструкции дает эту гарантию неявно, потому что если исключение выбрано, то объект не будет существовать. Таким образом, в типичном случае копирование - это «странный человек», который не предлагает надежную гарантию или лучше.

Это говорит о том, что сильная гарантия исключений часто трудно обеспечить, и, возможно, это не так полезно на практике. Я бы не стал поощрять людей автоматически предполагать, что CAS - лучшая вещь.

Если ваша цель состоит в том, чтобы избежать дублирования кода, лучшим способом является использование Правила нуля: http://en.cppreference.com/w/cpp/language/rule_of_three. В основном идея состоит в том, чтобы выбрать отдельных членов для вашего класса, так что компилятор сгенерировал конструктор/назначение copy/move - это поведение, которое вы хотите. Я понимаю, что этот код, возможно, является упражнением для понимания этих функций, но хорошо знать об этом, когда вы сами пишете код самостоятельно, а не учитесь.

Редактировать: Последнее примечание. Предполагая, что вы используете C++ 11, вообще говоря, рекомендованный способ использования CAS на самом деле не будет писать swap самостоятельно. Вместо этого вы должны написать конструктор перемещения (который вы должны в любом случае) и переместить назначение. Из этих двух функций общий std::swap сможет эффективно менять ваш класс. И тогда вы можете использовать общий код swap в своей реализации CAS. В некоторых случаях вы можете писать swap самостоятельно, но это обычно не обязательно. Более подробное обсуждение здесь: http://scottmeyers.blogspot.com/2014/06/the-drawbacks-of-implementing-move.html.

4

Копия замены подход является способом внедрить оператор копирования-присваивания с точки зрения повторного использования вашего свопа и копии const ructor, чтобы уменьшить повторяющийся код и добавить безопасность исключений.

Это сказал я заметил, некоторые вещи о вашем коде:

  • У вас нет деструкторов, так что вы будете течи ваших Foo* foo; объектов, когда ваши Actor s разрушаются.
  • В своем конструкторе копирования вы можете выделить и скопировать Foo за один шаг, не требуя промежуточного по умолчанию построенного Foo, которому вы назначаете.
  • Функция Swap - это член, который принимает два аргумента, что фактически означает, что он получает три аргумента. Он должен быть одним членом параметра и заменяться this или двумя параметрами, не являющимися членами.
  • Для согласования со стандартной библиотекой я рекомендую вызывать функцию свопинга swap, а не Swap, независимо от того, какой подход реализации вы принимаете.
  • В вашем свопа, предпочитают, чтобы удалить Bar обменивать на Bar, а не ее реализации в Actor класса: Другими словами, пусть Bar знают, как поменять себя и просто использовать эту функциональность.
+0

Должен ли использоваться копия swap? – 0x499602D2

1

Копия-и замены Назначение идиомы требует двух механизмов: копия c'tor и не-метание функцию подкачки.
Итак, ваш код следует за ним.

Идея состоит в том, чтобы сначала попытаться выполнить небезопасную операцию, вы создаете копию, просто определяя новый объект. Если он терпит неудачу и бросает, объект, который вы назначаете, остается неизменным, это состояние предсказуемо в случае ошибки. Это гарантия безопасности исключений.

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

И, наконец, деструктор временного очищает все и все оставшиеся ресурсы, так как метод обмена передал им это.

1

Я полагаю, что эта реализация хорошо, за исключением нескольких вещей:

1) Вы забыли поменять member1 в методе пользовательских Swap.

2) Идиома с копией и заменой обычно обеспечивает надежную гарантию исключения для operator=. Это означает, что он либо сбой исключается без изменения объекта, либо успешно выполняет присвоение. В вашем случае серьезная безопасность исключений вызывает сомнения, поскольку назначение Bar может потенциально вызвать исключение.

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

  • Нет связанных вопросов^_^