Я пытаюсь понять, существует ли какое-либо преимущество для возврата a const
ссылка. У меня есть функция факториала, которая обычно похожа на это:
unsigned long factorial(unsigned long n)
{
return (n == 0) ? 1 : n * factorial(n - 1);
}
Я предполагаю, что будет увеличение производительности, когда мы пройдем мимо const
ссылка и мы возвращаем a const
ссылка..., но const
- правильность всегда смущает меня.
const unsigned long & factorial(const unsigned long& n)
{
return (n == 0) ? 1 : n * factorial(n - 1);
}
Действительно ли это допустимо для возврата a const
ссылка? Кроме того, мог кто-то говорить мне: действительно ли это выгодно?
Это недействительно. Вы не можете вернуть ссылку на локальную переменную.
Компилятор MSVS C++ даже выдает следующее предупреждение:
main.cc : warning C4172: returning address of local variable or temporary
Не совсем уверен насчет GCC, но, вероятно, результат будет таким же.
Ссылка на константу здесь неверна - вы ' re возвращает ссылку на локальную переменную - здесь временную безымянную, либо 1
, либо результат n * factorial (n - 1)
. Поскольку ссылка относится к локальной переменной в функции, к тому времени, когда ссылка доходит до вызывающей стороны, эта локальная переменная уже вышла за пределы области видимости и является недопустимой.
Возвращает константную ссылку на большие структурированные типы, копирование которых вы хотите избежать, когда ссылка сохранится после выхода из функции. Обычно это означает возврат ссылки на аргумент или на переменную-член (в случае классов).
Единственный случай, когда допустимо возврат по ссылке const, - это если объект, который вы возвращаете, переживет вызов функции * (например, возврат члена класса, в котором функция была вызывается), и даже в этом контексте сомнительно, следует ли это делать, поскольку это позволит двум разным вызывающим абонентам получить доступ к одному и тому же месту в памяти, что превращает ситуацию в кошмар, если вы используете несколько потоков.
* ПРИМЕЧАНИЕ. В вашем случае возвращаемый элемент является локальной переменной и поэтому не переживет вызов функции. Следовательно, предоставленный вами код вызывает гнусное поведение undefined.
Ссылка const не быстрее, чем значение, если размер значения мал. В данном случае тип значения - long
, что IMO мало (например, от 4 до 8 байт): поэтому const-ссылка будет не быстрее. На самом деле она может быть медленнее, потому что для получения значения ссылки компилятору может понадобиться выдать код, который разыменует ссылку (как при разыменовании указателя).
Учитывая, что ссылка реализована (внутренне) как указатель, я ожидал бы получить лучшую производительность от передачи ссылок, чем от передачи значений, когда размер значения больше размера указателя (предполагая, что передача ссылки вообще законна: ссылка на локальную переменную, вышедшую из области видимости, не законна).
Возможно, но я бы никогда этого не сделал. Почему?
Потому что это хороший способ сделать ваш код нечитаемым .
Кроме того, компилятор оптимизирует его без этого взлома.
И, кроме того, разве у вас нет других «узких мест» для оптимизации в вашей программе?
Я имею в виду, если вы возьмете эту часть кода и посмотрите ее в сборке, вы увидите, что функция, значение и получение результата - это всего лишь несколько кодов операций. Как?
Что ж, 32-битное целое число поместится в регистр. Быстро как "mov eax, ...".
С другой стороны, ваша программа, вероятно, имеет другие проблемы с дизайном / алгоритмом, которые можно было бы оптимизировать ... Если только это не так просто, как программа "hello world".
Итак, я бы не стал заниматься этим, и каждый может бросить мне вызов.