передача по ссылке — параметр конструкции копирования c ++, передаваемый по значению

Я хочу, чтобы freeFunct делал неконстантные вещи для своей собственной копии объекта a.

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

Три разных способа объявить это приходят мне на ум.

У меня такое ощущение, что третье решение хуже.

Есть ли разница между первыми двумя?

Есть ли что-то лучше?

void freeFunct1(A a){
a.doStuff();
}

void freeFunct2(const A& a){
A b = a;
b.doStuff();
}

/**users of freeFunct3 are expected
*to give a copy of their variable:
*{
*    A b = a;
*    freeFunct3(b);
*}
*/
void freeFunct3(A& a){
a.doStuff();
}

2

Решение

Во-первых, как уже говорилось, не делай freeFunct3 если семантика свободной функции состоит в том, чтобы модифицировать только свой «собственный» объект.

Во-вторых, есть различия между freeFunct1 а также freeFunct2, относящийся к оптимизация хода [C ++, 11], исключительная безопасность, и потенциально размер кода.

С freeFunct2 (принимая по ссылке на const):

  1. Он всегда будет создавать новую копию аргумента, никогда не перемещать его [C ++ 11].
  2. Если копия конструкции A бросает исключение, он бросит внутри тела функции.
  3. Если AКопируется конструктор копирования (а функции нет), он будет расширен один раз, внутри тела функции (даже если функция вызывается из нескольких разных мест).

С freeFunct1 (принимая по значению):

  1. [C ++ 11] Вы можете избежать копирования, если A имеет конструктор перемещения, и вы передаете rvalue (например, вызов freeFunct1(A(args))).
  2. Если копия (или переместить) строительство A бросает исключение, он бросит на сайте вызова.
  3. Если AКонструктор копирования (или перемещения) встроен, он будет расширен многократно, на каждом сайте вызова.

В качестве альтернативы вы можете перегрузить ссылку на lvalue / rvalue, чтобы избежать ненужного копирования значений rvalue:

void freeFunct4(const A& a){
A b = a;
b.doStuff();
}
void freeFunct4(A&& a){
a.doStuff();
}
2

Другие решения

Первый вариант самый лучший: он позволяет вызывающей стороне выбирать, копировать или перемещать свой объект, поэтому он может быть более эффективным, если вызывающей стороне не нужно сохранять копию.

freeFunct1(a);             // "a" is copied and not changed
freeFunct1(std::move(a));  // "a" is moved and perhaps changed

Второй похож, но заставляет копию.

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

5

ИМО, первый самый лучший, а последний самый плохой.

Однако очень немногие люди настолько привыкли передавать по константной ссылке, что по умолчанию пишут # 2, хотя в этом случае им нужна копия, которой она пытается избежать.

2

Первый меняет только локальную копию. Второй такой же, как первый, но с дополнительным кодом. Третий внесет изменения в a видимый для абонента freeFunct3 поскольку это неконстантная ссылка. Если вызывается как в комментарии над функцией, то на самом деле она ничем не отличается от второй версии.

Так что, если вы просто хотите изменить локальную копию без передачи этих изменений вызывающей стороне, то я рекомендую первую версию.

1
По вопросам рекламы [email protected]