Доверие к оптимизации возвращаемого значения

Как вы используете оптимизацию возвращаемого значения?
Есть ли случаи, когда я могу доверять современному компилятору для использования оптимизации, или я всегда должен идти безопасным путем и возвращать указатель определенного типа/использовать ссылку в качестве параметра?

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


person Viktor Sehr    schedule 25.01.2010    source источник
comment
Имейте в виду, что компилятор может принять решение не этого делать, когда он определит, что RVO на самом деле не является оптимизацией в конкретном случае. Следовательно, вы должны доверять компилятору не только в том, что он сделает это, когда это полезно, но и в том, что он не сделает это, когда это неуместно.   -  person MSalters    schedule 25.01.2010
comment
Чтобы уточнить: распространенный случай, когда это неуместно, - это когда возвращаемый тип может быть передан в регистр, например. Radians класс. Метод RVO использует пространство, выделенное в стеке, и, таким образом, имеет накладные расходы на доступ к памяти.   -  person MSalters    schedule 26.01.2010
comment
@MSalters Хорошо, интересно узнать. По сути, интересующая меня оптимизация заключается в том, чтобы избежать, например, копирования std::vector‹›.   -  person Viktor Sehr    schedule 26.01.2010


Ответы (3)


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

Вы правы, компилятору это довольно легко выполнить оптимизацию, поэтому компиляторы почти всегда делают это. Единственные случаи, когда это «нельзя сделать», — это те, в которых оптимизация не применяется: RVO применяется только тогда, когда вы возвращаете безымянный временный объект. Если вы хотите вернуть именованную локальную переменную, вместо этого применяется NRVO, и, хотя для компилятора это немного сложнее реализовать, это выполнимо, и современные компиляторы не имеют с этим проблем.

person jalf    schedule 25.01.2010
comment
Особенно, если у вас есть 2 именованные переменные и вы выбираете одну для возврата во время выполнения, очевидно, что компилятор не может выполнить NRVO :) - person Matthieu M.; 25.01.2010
comment
Матье, я полагаю, то же самое касается двух безымянных выходов? (т. е. если (...) вернуть A() иначе вернуть B(); - person Viktor Sehr; 25.01.2010
comment
@Viktor: Нет, это RVO, а не NRVO. Будет построен только один из них. Таким образом, оба пути кода могут использовать одну и ту же память, которая является памятью, зарезервированной для возвращаемого значения. В этом суть RVO: напрямую создавать возвращаемое значение в зарезервированной для него памяти. - person MSalters; 26.01.2010
comment
Мэттье: нет, NRVO все еще может быть возможен, если есть две переменные, которые могут быть возвращены. Иногда в моих функциях есть оператор if. В одной ветке я создаю именованное значение, манипулирую им и возвращаю его; в другой ветке я делаю то же самое, но, возможно, использую другой конструктор. Нет никаких причин, по которым компилятор не мог бы оптимизировать это, но я уверен, что мой не может (Visual C++). - person Qwertie; 13.07.2010


Чтобы иметь наилучшие шансы на это, вы можете вернуть объект, созданный непосредственно в операторе return [кто-нибудь может вспомнить название этой идиомы - я забыл его]:

Foo f() {
    ....
    return Foo( ... );
}

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

person Community    schedule 25.01.2010