Должны ли небольшие простые структуры передаваться посредством ссылки const?

Мне всегда учили, что непримитивные типы должны передаваться по ссылке 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 версии?

Это так? Являются ли простые объекты лучшими, переданными по значению? Где должна быть проведена линия?

Ответы

Ответ 1

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

Ответ 2

Передача с помощью ссылки const позволяет избежать создания нового объекта. Если ваш конструктор является нетривиальным, например, он выделяет память, вам будет намного лучше передавать по ссылке const, чем по значению.

В мире С# вы принимаете это решение, выбирая, делать что-то классом или структурой. Классы используют ссылочную семантику, тогда как structs использует семантику значений. Все, что я когда-либо читал, говорит о том, что вы обычно должны делать все классы, если они не очень малы, т.е. Порядка 16 байт. Если вы ищете отсечку для того, чтобы передать значение по сравнению с константой const в С++, 16 байтов кажутся разумным порогом.

Ответ 3

Как и в политике, я передаю любой объект, который не является базовым типом данных C по ссылке const. Его гораздо легче запомнить этот путь.

Ответ 4

Более старый, но ясный, анализ ins-n-outs параметров прохождения можно найти на http://www.ddj.com/184403855. Конечно, С++ 0x устраняет много таких проблем с семантикой перемещения, но в документе дается много обоснований, почему желательно использовать семантику.

Ответ 5

Один из факторов, о которых я не упоминал, - это то, что подпрограмма будет делать с переданным значением. Если подпрограмма не будет развернута inline, управление данными, которые передаются по ссылке, потребует больше кода, чем манипулирование данными, которые передаются по значению. Если в поля пройденной структуры будет в среднем доступ менее чем один раз, эти дополнительные служебные данные будут небольшими по сравнению с накладными расходами на копирование структуры. Если они будут в среднем получать доступ во много раз каждый, было бы лучше иметь их в стеке. Если интерфейс уже задан как сквозная ссылка для структуры, которая имеет большой доступ, это может иметь смысл для вызываемой подпрограммы скопировать все интересующие части. С другой стороны, если вызываемая процедура собирается копировать много или всю структуру в любом случае, она также может быть передана по значению.

Ответ 6

Моя мысль заключается в том, что, передавая Vector2 по ссылке, это на самом деле дороже, чем передача по значению, поскольку компилятор теперь использует указатель и разыменование для доступа к const Vector2 & pos version

Было бы правдой, если бы вы передали объект, где size_of(object) < size_of(pointer_to_object). Например, char const& может быть дороже, чем char