C ++ передача по константной ссылке и возврат по константной ссылке - PullRequest
11 голосов
/ 10 июля 2010

Я пытаюсь понять, есть ли какая-либо польза от возврата ссылки const. У меня есть факториальная функция, которая обычно выглядит так:

unsigned long factorial(unsigned long n)
{
    return (n == 0) ? 1 : n * factorial(n - 1);
}

Я предполагаю, что произойдет увеличение производительности, когда мы перейдем по ссылке const и вернем ссылку const ... но const -корректность всегда меня смущает. 1010 *

const unsigned long & factorial(const unsigned long& n)
{
    return (n == 0) ? 1 : n * factorial(n - 1);
}

Допустимо ли возвращать ссылку const? Кроме того, может кто-нибудь сказать мне: это полезно?

Ответы [ 5 ]

9 голосов
/ 10 июля 2010

Это неверно.Вы не можете вернуть ссылку на локальную переменную.

MSVS C ++ даже не выдает следующее предупреждение:

main.cc : warning C4172: returning address of local variable or temporary

Не совсем уверен насчет GCC, но, вероятно, результат будет таким же.

8 голосов
/ 10 июля 2010

Константная ссылка не быстрее значения, если размер значения невелик. В этом случае тип значения равен long, что является малым значением IMO (например, от 4 до 8 байтов): поэтому ссылка на const не будет быстрее. На самом деле это может быть медленнее, потому что для получения значения ссылки компилятору может потребоваться выдать код, который будет разыменовывать ссылку (например, разыменование указателя).

Учитывая, что ссылка реализована (внутренне) как указатель, я ожидал бы получить лучшую производительность от передачи ссылок, чем от передачи значений, когда размер значения больше размера указателя (при условии, что он даже разрешено передавать ссылку: ссылка на локальную переменную, которая вышла из области видимости, недопустима).

6 голосов
/ 10 июля 2010

Здесь константная ссылка неверна - вы возвращаете ссылку на локальную переменную - здесь не указано временное значение, либо 1, либо результат n * factorial(n - 1).Поскольку ссылка на локальную переменную в функции, к тому времени, когда ссылка попадает в вызывающую функцию, эта локальная переменная уже вышла из области действия и становится недопустимой.

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

3 голосов
/ 10 июля 2010

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

* ПРИМЕЧАНИЕ.элемент, который вы возвращаете, является локальной переменной и, следовательно, не переживет вызов функции.Следовательно, код, который вы предоставили, вызывает гнусное неопределенное поведение.

1 голос
/ 10 июля 2010

Возможно, я бы никогда этого не сделал. Почему?

Потому что это хороший способ сделать ваш код нечитаемым .

Кроме того, компилятор оптимизирует без этого хака.

И, кроме того, разве у вас нет других "узких мест" для оптимизации в вашей программе?
Я имею в виду, что если вы возьмете эту часть своего кода и посмотрите на нее в сборке, вы увидите, что передача функции значения и получение результата - это всего лишь несколько кодов операций. Как?
Хорошо, 32-разрядное целое число поместится в регистр. Быстро, как "mov eax, ...".
С другой стороны, ваша программа, вероятно, имеет другие проблемы с дизайном / алгоритмом, которые могут быть оптимизированы ... Если это не так просто, как в программе "Привет, мир".

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

...