Ответ 1
Комитет по стандартизации потратил большие усилия на создание формулировок, чтобы движения происходили только в двух случаях:
- Если это безопасно, сделайте это.
- Когда пользователь явно запрашивает (через
std::move
или аналогичный перевод).
Параметр значения, несомненно, будет уничтожен в конце функции. Поэтому возвращение его движением явно безопасно; он не может быть затронут другим кодом после возврата (если только вы не намеренно пытаетесь сломать вещи, и в этом случае вы, вероятно, вызвали поведение undefined). Поэтому он может быть перемещен из возврата.
A &&
переменная может относиться к временному. Но это может быть ссылка на lvalue (именованная переменная). Поэтому нецелесообразно переходить от него; первоначальная переменная может скрываться. И так как вы явно не просили перейти от него (т.е. Вы не вызывали std::move
в этой функции), движение не может происходить.
Единственный раз, когда переменная &&
будет неявно перемещена из (т.е. без std::move
), когда вы ее возвращаете. std::move<T>
возвращает a T&&
. Для этого возвращаемого значения является законным, чтобы вызвать конструктор перемещения, потому что это возвращаемое значение.
Теперь очень сложно вызвать A func(A &&a)
с lvalue без вызова std::move
(или эквивалентного перевода). Так что технически это должно быть хорошо для параметров типа &&
, которые должны быть неявно перемещены. Но комитет по стандартам хотел, чтобы действия были явными для типов &&
, чтобы убедиться, что движение не косвенно происходит в рамках этой функции. То есть он не может использовать знание вне функции о том, откуда приходит &&
.
В общем случае вы должны принимать только параметры &&
в двух случаях: либо вы пишете конструктор перемещения (или переместите оператор присваивания, но даже это можно сделать по значению), либо вы пишете пересылку функция. Могут быть несколько других случаев, но вы не должны брать &&
в тип, если у вас нет чего-то особенного. Если A
является подвижным типом, то просто возьмите его по значению.