2010-07-22 8 views
14

Я всегда учил, что непримитивные типы должны быть переданы по константной ссылке, а не по значению, где это возможно, а именно:Должны ли передаваться небольшие простые структуры по ссылке 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 по ссылке, это на самом деле дороже, чем передача по значению, так как компилятор теперь использует указатель и разыменования для доступа к константный Vector2 & поз версия?

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

+0

Обратите внимание, что если ваш тип класса имеет объявленные пользователем конструкторы, это не POD. –

+6

Общее правило: Pass by const-reference, если 'sizeof (T) <= sizeof (void *)' или 'T' является примитивным. – GManNickG

+2

@GMan, вы избили меня до него (и +1). Хотя, я бы обобщил, что он, вероятно, меньше или равен размеру слова процессора. И нужно проверить спецификации процессора, чтобы узнать оптимальный размер. Если я не ошибаюсь, компиляторы могли бы потенциально оптимизировать const ref для передачи по значению в некоторых случаях, независимо от размера. Я бы предположил, что это особенно верно в C++ 0x с учетом новой семантики перемещения. –

ответ

7

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

+0

+1 для профилирования - его единственный способ определить, что лучше –

1

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

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

+1

Типы POD не имеют нетривиальных конструкторов копирования (или даже нетривиальных конструкторов или деструкторов по умолчанию). –

+2

OP не сказал явно сказать тип POD. Он сказал ** простой ** пользовательский тип, а затем дал пример, указавший, что у него есть конструктор. –

0

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

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

+2

Это также может быть правдой, если повторное разыменование приведет к большему количеству накладных расходов, чем сохраняется, если не передать столько данных. Или если эта ссылка предотвращает оптимизацию из-за проблем с псевдонимом. Или, если ссылка повреждает вашу местность. –

1

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

1

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

1

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

Смежные вопросы