Так как у нас есть семантика перемещения в C++, в наше время обычно сделать
void set_a(A a) { _a = std::move(a); }
Обоснование - это если a
rvalue, копия будет игнорироваться и будет всего одно перемещение.
Но что происходит если a
lvalue? Кажется, что будет конструкция копии, и затем присвоение перемещения (принимающий A имеет надлежащий оператор присваивания перемещения). Переместитесь присвоения могут быть дорогостоящими, если объект имеет слишком много членских переменных.
С другой стороны, если мы делаем
void set_a(const A& a) { _a = a; }
Будет всего одно присвоение копии. Мы можем сказать, что этот путь предпочтен по идиоме передачи значением, если мы передадим lvalues?
Удобочитаемость в объявлении:
void foo1( A a ); // easy to read, but unless you see the implementation
// you don't know for sure if a std::move() is used.
void foo2( const A & a ); // longer declaration, but the interface shows
// that no copy is required on calling foo().
Производительность:
A a;
foo1( a ); // copy + move
foo2( a ); // pass by reference + copy
Обязанности:
A a;
foo1( a ); // caller copies, foo1 moves
foo2( a ); // foo2 copies
Для типичного встроенного кода обычно нет никакого различия при оптимизации. Но foo2 () мог бы сделать копию только на определенных условиях (например, вставить в карту, если ключ не существует), тогда как для foo1 () копия будет всегда делаться.