Ответ 1
Вы абсолютно правы, что пример int&& GetInt()
неверен и возвращает ссылку на уничтоженный объект. Однако, если я не пропустил его, ссылка, которую вы опубликовали, на самом деле не показывает код, возвращающий ссылку на локальную переменную. Вместо этого я вижу ссылку на возвращаемую глобальную переменную, которая в порядке.
Вот как вы используете семантику перемещения при возврате:
std::string func()
{
std::string rv;
/* ... */
return rv;
}
Обычно вы не должны использовать std::move()
при возврате объекта. Причиной этого является то, что перемещение уже неявно разрешено в любое время RVO, и использование std::move()
будет подавлять RVO. Поэтому использование std::move()
никогда не будет лучше и часто будет хуже, чем просто нормально вернуться.
Опять же, использование std::move()
может быть хуже, чем просто называть возвращаемую переменную, поскольку она подавляет оптимизацию возвращаемого значения. Оптимизация возвращаемого значения позволяет вернуть объект вызывающей стороне без необходимости копировать этот объект
в выражении
return
в функции с возвращаемым типом класса, когда выражение - это имя энергонезависимого автоматического объекта (другое чем параметр функции или catch-clause) с тем же cv-unqualified type как возвращаемый тип функции, копирование/перемещение операция может быть опущена путем непосредственного конструирования автоматического объекта в возвращаемое значение функции- [class.copy] 12.8/31
Но использование std::move()
не позволяет возвращенному выражению быть именем возвращаемого объекта. Вместо этого выражение более сложное, и языку больше не разрешается придавать ему особую управляемость.
Причина просто именования объекта не хуже, чем использование std::move()
, потому что существует другое правило, в котором выражение, которое говорит, выражение уже может рассматриваться как rvalue без необходимости std::move()
.
Когда критерии для исключения операции копирования выполняются или будут сэкономленные за тот факт, что исходный объект является параметром функции, и подлежащий копированию объект обозначается значением lvalue, перегрузкой разрешение для выбора конструктора для копии сначала выполняется как будто объект был обозначен rvalue.