Явная копия в copy-and-swap

138
22 января 2020, 02:10

Смотрю в википедии на описание copy-and-swap и его же в отдельной статье:

RFive& operator=(const RFive& other)
{
    Rfive tmp(other);
    swap (*this, tmp);
    return *this;
}

Мне интересно, зачем создавать копию явно внутри метода

RFive& operator=(const RFive& other)
{
    Rfive tmp(other);

если можно создать копию неявно просто передав аргумент по значению (т. е. без ссылки)

RFive& operator=(RFive other)

У этого варианта есть какие-то скрытые недостатки?

Я бы вообще как-то так сделал:

RFive & operator = (RFive other)
{
    return this->operator=(std::move(other));
}

Нормально? Естественно, только для случая, когда есть

RFive & operator = (RFive &&other)
Answer 1

Комбинация

RFive& operator=(RFive other)
RFive& operator=(RFive &&other)

о которой вы ведете речь, нежизнеспособна вообще. Такой вариант будет приводить к неоднозначности overload resolution при вызове с std::move в качестве аргумента (http://coliru.stacked-crooked.com/a/1ae64b244f99d5f7)

В остальном ваш вопрос по сути является дупликатом Захват аргументов

У вас на выбор есть два варианта достаточно эффективной поддержки присваивания с учетом move semantics.

  1. Либо писать две версии оператора

    RFive& operator=(const RFive &other)
    {
      // copy from `other`
    }
    RFive& operator=(RFive &&other)
    {
      // move from `other`
    }
    
  2. Либо - "ленивый" вариант - только одну версию

    RFive& operator=(RFive other)
    {
      // move from `other`
    }
    

    Эта единственная версия во втором варианте покрывает функциональность обеих версий оператора из первого варианта, но с небольшим(?) накладным расходом - один дополнительный промежуточный объект и один дополнительный move в контексте перемещения.

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

Answer 2

У этого варианта есть два радикальных недостатка - создание и разрушение передаваемого объекта будет каждый раз вставляться в код, который вызывает эту функцию, а не один раз в теле самой функции. Это особенно плохо, если класс импортируется из динамической библиотеки. Временный объект создается всегда, даже в ситуации, когда его создания можно было бы избежать при использовании раздельных копирующего и перемещающего конструктора RFive five{}; other = ::std::move(five);

READ ALSO
Up вектор в реализации камеры

Up вектор в реализации камеры

В примере к видовой матрице указано:

150
Строки вводятся не ожидаемым образом

Строки вводятся не ожидаемым образом

У меня есть код, в котором я ввожу число N, а потом просто ввожу в цикле по N строки, состоящие из пробелов, цифр, скобок и дефисовПотом я хочу...

117
c++ различие операторов?

c++ различие операторов?

Подскажите, чем отличаются данные фрагменты кода

129
Возврат из потока POSIX

Возврат из потока POSIX

Нужно вернуть данные из потоковой функции:

110