Ответ 1
Эти фрагменты кода в основном эквивалентны. Это:
Foo&& rf = Foo();
связывает временную ссылку, которая продлевает время жизни временного ресурса до ссылки. Foo
будет уничтожаться только тогда, когда rf
выходит за рамки. С тем же самым поведением вы получаете:
Foo f;
за исключением того, что в последнем примере f
инициализируется по умолчанию, но в предыдущем примере rf
инициализируется значением. Для некоторых типов эти два эквивалентны. Для других это не так. Если бы вы написали Foo f{}
, то это различие исчезнет.
Одно из оставшихся различий относится к копированию:
Foo give_a_foo_rv() {
Foo&& rf = Foo();
return rf;
}
Foo give_a_foo() {
Foo f{};
return f;
}
RVO не разрешается выполнять в первом примере, поскольку rf
не имеет тот же тип, что и тип возврата give_a_foo_rv()
. Более того, rf
даже не будет автоматически перемещен в тип возвращаемого значения, потому что он не является объектом, поэтому он не имеет автоматической продолжительности хранения, поэтому дополнительная копия:
Foo f = give_a_foo_rv(); // a copy happens here!
Foo g = give_a_foo(); // no move or copy
кажется очевидным, что копий не будет.
Это полностью зависит от того, что делает движение Foo
. Если Foo
выглядит следующим образом:
struct Foo {
Foo() = default;
Foo(Foo const& ) = default;
Foo& operator=(Foo const& ) = default;
// some members
};
тогда перемещение a Foo
все еще копирует.
И да, во втором примере это вполне нормально std::move(f)
. Вам не нужен объект типа rvalue для ссылки на T
на move
. Это серьезно ограничило бы полезность перемещения.