Является ли ссылочный параметр rvalue, возвращаемый значением, значением xvalue?

Насколько я понимаю, в следующей функции выражение foo в заявлении return foo; является значением xvalue, потому что объект, который он обозначает, истекает (даже если foo является lvalue в предыдущих утверждениях):

Foo bar()
{
Foo foo;
change(foo);
return foo;
}

Такая истекающая стоимость не покрывается Какие выражения создают значения xvalue?.

Это изменится в следующем случае?

Foo bar(Foo&& foo)
{
change(foo);
return foo;
}

Является foo xvalue в операторе возврата? И, в частности, это кандидат на переезд? А для РВО? Или следует использовать return std::move(foo)?

Я не знаю, каково формальное правило для классификации выражения foo как xvalue в операторе return первого случая, поэтому я не могу проверить его во втором.

2

Решение

В этой функции foo является именующий типа «rvalue ссылка на FooMsgstr «Когда вы его возвращаете, так как копия должна быть построена (из-за типа возвращаемого значения), вы создаете совершенно новое значение, которое делает bar(...) prvalue, согласно §3.10.1.5:

Prvalue («чистое» rvalue) — это rvalue, которое не является xvalue. [Пример: результат вызова функции, тип возвращаемой которой не является ссылкой, является предварительным значением. Значение литерала, такого как 12, 7.3e5 или true, также является prvalue. — конец примера]

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

И да, здесь применяется RVO, при условии, что ход не выбран первым. Здесь нет ничего особенного. Согласно §12.8.31:

Такое исключение операций копирования / перемещения, называемое разрешением копирования, допускается при следующих обстоятельствах (которые могут быть объединены для удаления нескольких копий):

  • в операторе возврата в функции с типом возврата класса, когда выражение является именем энергонезависимого автоматического объекта (отличного от параметра функции или оператора catch) с тем же cv-неквалифицированным типом, что и тип возврата функции, операцию копирования / перемещения можно опустить, создав автоматический объект непосредственно в возвращаемое значение функции
[…]

Чтобы уточнить, foo само по себе это lvalue, но утверждение:

return foo;

в конечном итоге результаты (из bar(...) expression) в prvalue из-за того факта, что, учитывая тот тип возвращаемого значения, выражение эквивалентно:

return Foo(foo);

это означает, что временное значение, скопированное из foo возвращается из функции bar,


Перечитывая ответ, он все еще не имеет смысла для меня. Вы говорите: из-за того, что внутри функции foo является lvalue, выражение return foo не является кандидатом на конструкцию перемещения, и выбран конструктор копирования. Почему это верно в одном случае, а не в другом?

При возвращении foo Вы должны создать новый Foo значение (потому что вы возвращаете копию) из именующий ссылка foo, Это делается неявно конструктором копирования. Так return foo; эквивалентно return Foo(foo), При условии foo является lvalue, выбран конструктор копирования (а не конструктор перемещения).

Теперь, когда у вас есть это новое временное значение (построенный из foo), само значение, которое выходит из выражения bar(...), это prvalue. Итак, когда вы делаете:

auto res = bar(...);

Вы должны построить Foo скопировать из prvalue. Поскольку prvalue также является rvalue, выбирается конструктор со ссылочным параметром rvalue (конструктор перемещения).

2

Другие решения


По вопросам рекламы [email protected]