Ответ 1
Да, простые объекты должны передаваться по значению. Строка должна быть построена в соответствии с архитектурой. Если есть сомнения, профиль.
Мне всегда учили, что непримитивные типы должны передаваться по ссылке const, а не по значению, где это возможно, например:
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 по ссылке, это на самом деле дороже, чем передача по значению, поскольку компилятор теперь использует указатель и разыменование для доступа к const Vector2 & pos версии?
Это так? Являются ли простые объекты лучшими, переданными по значению? Где должна быть проведена линия?
Да, простые объекты должны передаваться по значению. Строка должна быть построена в соответствии с архитектурой. Если есть сомнения, профиль.
Передача с помощью ссылки const позволяет избежать создания нового объекта. Если ваш конструктор является нетривиальным, например, он выделяет память, вам будет намного лучше передавать по ссылке const, чем по значению.
В мире С# вы принимаете это решение, выбирая, делать что-то классом или структурой. Классы используют ссылочную семантику, тогда как structs использует семантику значений. Все, что я когда-либо читал, говорит о том, что вы обычно должны делать все классы, если они не очень малы, т.е. Порядка 16 байт. Если вы ищете отсечку для того, чтобы передать значение по сравнению с константой const в С++, 16 байтов кажутся разумным порогом.
Как и в политике, я передаю любой объект, который не является базовым типом данных C по ссылке const. Его гораздо легче запомнить этот путь.
Более старый, но ясный, анализ ins-n-outs параметров прохождения можно найти на http://www.ddj.com/184403855. Конечно, С++ 0x устраняет много таких проблем с семантикой перемещения, но в документе дается много обоснований, почему желательно использовать семантику.
Один из факторов, о которых я не упоминал, - это то, что подпрограмма будет делать с переданным значением. Если подпрограмма не будет развернута inline, управление данными, которые передаются по ссылке, потребует больше кода, чем манипулирование данными, которые передаются по значению. Если в поля пройденной структуры будет в среднем доступ менее чем один раз, эти дополнительные служебные данные будут небольшими по сравнению с накладными расходами на копирование структуры. Если они будут в среднем получать доступ во много раз каждый, было бы лучше иметь их в стеке. Если интерфейс уже задан как сквозная ссылка для структуры, которая имеет большой доступ, это может иметь смысл для вызываемой подпрограммы скопировать все интересующие части. С другой стороны, если вызываемая процедура собирается копировать много или всю структуру в любом случае, она также может быть передана по значению.
Моя мысль заключается в том, что, передавая Vector2 по ссылке, это на самом деле дороже, чем передача по значению, поскольку компилятор теперь использует указатель и разыменование для доступа к const Vector2 & pos version
Было бы правдой, если бы вы передали объект, где size_of(object) < size_of(pointer_to_object)
. Например, char const&
может быть дороже, чем char