Почему требования RVO такие строгие?

Еще одно "почему должны std::move предотвратить (безымянный) возврат-оптимизацию?"

Почему std::move предотвращает RVO? объясняет, что стандарт специально требует, чтобы объявленный тип возвращаемого значения функции соответствовал типу выражения в return заявление. Это объясняет поведение соответствующих компиляторов; однако, это не объясняет обоснование ограничения.

Почему правила для RVO не делают исключения для случая, когда тип возвращаемого значения функции T и тип return выражение T&&?

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

Я также знаю, что return std::move(...) не требуется, поскольку C++11 уже требует использования семантики перемещения, когда RVO не может быть применен. Тем не менее, почему бы не допустить явного запроса на оптимизацию вместо того, чтобы превратить его в пессимизацию?


(В сторону: почему return-value-optimization а также rvo теги не синонимы?)

1 ответ

Решение
auto foo() -> T&&;

auto test() -> T
{
    return foo();
}

Вы говорите, что в этом случае следует разрешить применение RVO. Однако рассмотрим эту правовую реализацию foo:

T val;

auto foo() -> T&&
{
   return static_cast<T&&>(val); // because yes, it's legal
}

Мораль: только с prvalues ​​вы точно знаете, что у вас есть временное и самое важное, вы знаете точный срок службы временного, чтобы вы могли исключить его строительство и разрушение. Но с xvalues ​​(например, T&& вернитесь) вы не знаете, действительно ли это связано с временным, вы не знаете, когда это значение было создано и когда оно выходит из области видимости, или даже если вы знаете, что вы не можете изменить его точку построения и разрушения, как приведенный выше пример.

Я не уверен, что полностью понимаю. Если бы RVO было разрешено применять к test()почему это будет хуже, чем если бы тест сделал: T temp = foo(); return temp; что позволит NRVO?

Дело не в том, что это хуже. Это просто невозможно. С вашим примером temp является локальной переменной в функции, где вы хотите применить NRVO, т.е. test, Как таковой, это объект, полностью "известный" в контексте test, его время жизни известно, нормальная точка ctor и dtor известна. Таким образом, вместо создания temp переменная в кадре стека test он создается в кадре стека вызывающей стороны. Это означает, что нет копии объекта из стекового фрейма test в стек стека вызывающей стороны. Также, пожалуйста, посмотрите, что в этом примере foo() совершенно не имеет значения. Это могло быть что угодно в инициализации temp:

auto test() -> T
{
    T temp = /*whatever*/;

    return temp; // NRVO allowed
}

Но с return foo() вы не можете удалить копию просто потому, что не можете знать, к какому объекту привязана обратная ссылка. Это может быть ссылка на любой объект.

Другие вопросы по тегам