Подтвердить что ты не робот

Контрпродуктивно передавать примитивные типы по ссылке?

Возможный дубликат:
Лучше ли передавать по значению или по ссылке для базовых типов данных?
Причины не передавать простые типы по ссылке?

Я провел некоторое тестирование, где у меня было два сценария, каждый из которых имел две идентичные функции: один передавал параметр по ссылке, а другой - по значению. Сценарий со строками показал значительное увеличение производительности (потому что создается копия строки, вызывая конструктор), тогда как тест с длинным не показывал увеличения производительности при передаче значения по ссылке. Фактически, иногда производительность была хуже.

Ожидается ли это с помощью примитивных типов? Нет ли точки, передающей их по ссылке?

Я ожидал, что копия примитивного типа будет сделана, когда не будет использоваться по ссылке, и поэтому ожидается небольшое повышение производительности.

4b9b3361

Ответ 1

Вы получаете лучшую производительность от передачи примитивных типов по значению. Это происходит потому, что:

  • примитивы неприменимы, поэтому стоимость копии зависит от размера
  • примитивы малы, только double и long long больше, чем ссылка в большинстве сред.
  • pass-by-value избегает сглаживания, позволяя оптимизатору действительно выполнять свою работу

Эта последняя точка часто упускается из виду, но может иметь существенное значение.

Ответ 2

Да, это ожидаемое поведение. Когда вы передаете параметры по ссылке, вы фактически передаете адрес переменной (например, с указателем). Обычно адрес представляет собой целое число 4 или 8 байтов, поэтому, если ваш примитивный тип не будет больше, вы не получите какого-либо улучшения производительности (и даже если оно больше, вы, вероятно, не будете)

Ответ 3

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

Ответ 4

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

Таким образом, существует шаг косвенности, который отсутствует при передаче параметров по значению, что может привести к ухудшению производительности, но это действительно туманно, поскольку оптимизация компилятора возникает. Подумайте о том, что вы передаете указатель, каждый раз, когда вам нужно значение, вы должны извлекать указатель из стека, а затем извлекать указанное значение (так что есть два доступа), тогда как с обычным параметром у вас есть только один.

В любом случае ссылка используется для целей, которые, безусловно, отличаются от производительности.

Ответ 5

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

Я увидел код, в котором я работал, что-то вроде этого:

void SomeClass::FindLength(int &len)
{
     listEntry* list = theList;   // theList is a member variable. 
     len = 0;
     while (list)
     {
         len++;
         list = list->next;
     }
 }

Изменяя код:

void SomeClass::FindLength(int &len)
{
     listEntry* list = theList;   // theList is a member variable. 
     int tempLen = 0;
     while (list)
     {
         tempLen++;
         list = list->next;
     }
     len = tempLen;
 }

весь код работал примерно на 30% быстрее и вызывался из множества мест (и я думаю, что в середине было какое-то условие if, поэтому мы не могли просто отслеживать длину). И поскольку это было частью функции API, изменить подпись функции не удалось.

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

Ответ 6

Поскольку вы использовали тег c, я думаю, вы говорите о указателях (не явных ссылках на С++).

С указателями у вас есть два доступа к памяти: указатель и указанное значение. Таким образом, нет особых выигрышей. Более того, компилятор может сделать больше оптимизаций со значениями: например, нет проблем с псевдонимом.

Ответ 7

Ожидается ли это с помощью примитивных типов?

Я бы сказал абсолютно. У них нет конструкторов, поэтому их не нужно называть.

Нет ли точки, передающей их по ссылке?

Существует: когда вы хотите иметь выходные параметры, то в С++ передача по ссылке считается более эффективной, чем передача указателя.

Я ожидал, что копия примитивного типа будет сделана, когда не будет использоваться по ссылке, и поэтому ожидается небольшое повышение производительности.

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