2010-03-15 2 views
18

Допустим, у меня есть функция, где параметр передается значением вместо const-reference. Кроме того, предположим, что внутри функции используется только значение, то есть функция не пытается ее модифицировать. В этом случае компилятор сможет определить, что он может передать значение по const-reference (по соображениям производительности) и сгенерировать код соответственно? Есть ли компилятор, который это делает?Компилятор оптимизирует параметры функции, переданные значением?

+1

Обратите внимание, что обычно * компилятор * учитывает только один TU за раз. На практике оптимизация, которая включает вызывающего, делающего что-то другое, в зависимости от того, что происходит в вызываемом вызове, работает только в том случае, если определение функции доступно в TU вызывающего абонента и/или с оптимизацией времени соединения. –

+0

Связанный вопрос: http://stackoverflow.com/questions/2043974 –

ответ

14

Если вы передаете переменную вместо временного, компилятору не удастся оптимизировать копию, если его конструктор делает все, что вы заметили при запуске программы («наблюдаемое поведение»: входы/выходы или изменение изменчивых переменных).

Помимо этого, компилятор может свободно делать все, что он хочет (он должен только напоминать наблюдаемое поведение as-if он бы не оптимизировал вообще).

Только когда аргумент является rvalue (наиболее временным), компилятору разрешено оптимизировать копию в параметре by-value, даже если конструктор копирования имеет наблюдаемые побочные эффекты.

+0

Ум, не копирует ли освобождение от правила as-if? Я думал, что копирование - единственное, что может устранить компилятор, не беспокоясь о последствиях. – sbi

+0

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

+2

@sbi копирование освобождается, если вы копируете из rvalue. Если вы скопируете из lvalue, это не так. Если вы передаете rvalue, а компилятор заключает в себе код вызываемой функции, он может оптимизировать все, что захочет (на самом деле, я видел, что GCC оптимизирует сотни конвейерных линий с тремя или четырьмя вложенными вызовами только в две или три строки) , См. 12.8/15 в спецификации C++ 03. –

7

Только в том случае, если функция не экспортируется, есть вероятность, что компилятор преобразует вызов по ссылке на вызов по значению (или наоборот).

В противном случае, из-за соглашения о вызове, функция должна поддерживать семизначную/ссылочную семантику.

+2

Но, конечно же, его можно было бы оптимизировать, хотя визуальная версия функции не была бы оптимизирована. –

-1

Этот пост является отличным ориентиром для такого рода оптимизации: http://cpp-next.com/archive/2009/08/want-speed-pass-by-value/

+0

Я думаю, что вам не хватает смысла в статье (по крайней мере, в контексте этого вопроса). В этой статье копия будет сделана так или иначе, и она * будет изменена *. – UncleBens

+0

UncleBens: Я понимаю, что вы имеете в виду, но я думал, что сообщение в блоге проливает свет на оптимизацию, на которую способен компилятор, и поэтому я чувствовал, что это не совсем не по теме. Подумайте над комментарием «это означает, что мы можем полностью и навсегда свалить старый проход-на-const-reference & copy operator =?», На что отвечает Д. Абрахамс: «На самом деле, да! Дамп вчера. » – Francesco

0

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

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

1

Мне не известны общие гарантии того, что это будет сделано, но если вызываемая функция встроена, тогда это позволит компилятору увидеть, что делается ненужная копия, и если уровень оптимизации достаточно, операция копирования будет устранена. GCC может это сделать как минимум.

Возможно, вам стоит подумать о том, имеет ли класс этого параметра конструктор копии или нет. Если это не так, то разница в производительности между передачей по значению и pass-by-const-ref, вероятно, небезопасна.

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

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

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