Мне всегда преподавали, что нетипы примитивов должны быть переданы ссылкой константы, а не значением, если это возможно, т.е.:
void foo(std::string str);//bad
void foo(const std::string &str);//good
Но я думал сегодня, что, возможно, на самом деле некоторые простые определяемые пользователем типы могут на самом деле быть лучше переданы значением, например:
class Vector2
{
public:
float x, y;
...constructors, operators overloads, utility methods, etc...
};
void foo(Vector2 pos);
void foo(const Vector2 &pos);//is this really better than by value?
void foo(float x, float y);//after all isn't by value effectively doing this?
Моя мысль - то, что путем передачи Vector2 ссылкой, это на самом деле более дорого, чем передача значением, так как компилятор теперь использует указатель и разыменовывает для доступа к версии Vector2 &pos константы?
Имеет место это? Простые объекты лучше всего от переданного значением? Где линия должна быть проведена?
Да, простые объекты должны передаваться по значению. Линия должна быть проведена в соответствии с архитектурой. Если есть сомнения, профиль.
Передача по ссылке const позволяет избежать создания нового объекта. Если ваш конструктор нетривиален, например, выделяет память, вам будет гораздо лучше передавать по const-ссылке, чем по значению.
В мире C# вы принимаете это решение, выбирая, сделать ли что-то классом или структурой. Классы используют семантику ссылок, а структуры - семантику значений. Все, что я когда-либо читал, говорит о том, что обычно следует выбирать класс, если только он не очень мал, т.е. порядка 16 байт. Если вы ищете границу, когда в C++ следует передавать по значению, а не по const-ссылке, то 16 байт кажется разумным порогом.
Просто в качестве правила я передаю любой объект, который не является базовым типом данных C, по ссылке const. Так гораздо легче запомнить.
Более старый, но внятный анализ особенностей передачи параметров можно найти на http://www.ddj.com/184403855. Конечно, c++0x избавляет от многих подобных проблем с помощью семантики перемещения, но в статье приводится много обоснований того, почему семантика перемещения желательна.
Я считаю, что передача Vector2 по ссылке на самом деле дороже, чем передача по значению, поскольку теперь компилятор использует указатель и разыменование для доступа к версии const Vector2 & pos
Было бы верно, если бы вы передали объект, где size_of (object)
char const &
может быть дороже, чем char
Один фактор, о котором я не упоминал, - это то, что процедура будет делать с переданным значением. Если подпрограмма не развернута в строку, для манипулирования данными, которые передаются по ссылке, потребуется больше кода, чем для манипулирования данными, которые передаются по значению. Если к полям переданной структуры в среднем будет осуществляться доступ менее одного раза к каждому, эти дополнительные накладные расходы будут небольшими по сравнению с накладными расходами на копирование структуры. Если к каждому из них в среднем будет обращаться много раз, вероятно, будет лучше, если они будут в стеке. Если интерфейс уже настроен как проход по ссылке для структуры, к которой часто обращаются, для вызываемой подпрограммы может иметь смысл скопировать все части, которые представляют интерес. С другой стороны, если вызываемая подпрограмма в любом случае собирается скопировать большую часть или всю структуру, ее также можно передать по значению.