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