В чем разница между std :: move и std :: forward - PullRequest
151 голосов
/ 12 марта 2012

Я видел это здесь: Конструктор Move вызывает базовый класс Конструктор Move

Может кто-нибудь объяснить:

  1. разница между std::move и std::forward, предпочтительно с некоторыми примерами кода?
  2. Как легко об этом думать и когда использовать какой

Ответы [ 3 ]

143 голосов
/ 15 марта 2012

std::move берет объект и позволяет рассматривать его как временное (значение).Хотя это не семантическое требование, обычно функция, принимающая ссылку на rvalue, делает ее недействительной.Когда вы видите std::move, это означает, что значение объекта не должно использоваться впоследствии, но вы все равно можете присвоить новое значение и продолжить его использование.

std::forward имеет один вариант использования: toприведите шаблонный параметр функции (внутри функции) к категории значений (lvalue или rvalue), используемой вызывающей стороной для его передачи.Это позволяет передавать аргументы rvalue как значения rvalue, а lvalues ​​- как значения lvalue - схему, называемую «совершенной пересылкой».1012 * Как упоминает Говард, есть также сходства, поскольку обе эти функции просто приводятся к ссылочному типу.Но кроме этих конкретных случаев использования (которые охватывают 99,9% полезности приведенных ссылок на rvalue), вы должны использовать static_cast напрямую и написать хорошее объяснение того, что вы делаете.

57 голосов
/ 12 марта 2012

И std::forward, и std::move - не что иное, как приведение.

X x;
std::move(x);

Выше приведено выражение lvalue x типа X к выражению rvalue типа X (точнее xvalue). move также может принимать значение:

std::move(make_X());

и в этом случае это функция тождества: принимает значение типа X и возвращает значение типа X.

С помощью std::forward вы можете выбрать пункт назначения до некоторой степени:

X x;
std::forward<Y>(x);

Приводит выражение lvalue x типа X к выражению типа Y. Существуют ограничения на то, что может быть Y.

Y может быть доступной Базой X или ссылкой на Базу X. Y может быть X, или ссылкой на X. Нельзя отбрасывать cv-квалификаторы с помощью forward, но можно добавлять cv -qualifiers. Y не может быть типом, который просто конвертируется из X, кроме как через доступное базовое преобразование.

Если Y является ссылкой lvalue, результатом будет выражение lvalue. Если Y не является ссылкой lvalue, результатом будет выражение rvalue (точнее xvalue).

forward может принимать аргумент rvalue, только если Y не является ссылкой lvalue. То есть вы не можете привести значение к значению lvalue. Это из соображений безопасности, поскольку это обычно приводит к висящим ссылкам. Но приведение rvalue к rvalue возможно и разрешено.

Если вы попытаетесь указать Y для чего-то, что не разрешено, ошибка будет обнаружена во время компиляции, а не во время выполнения.

20 голосов
/ 12 марта 2012

std::forward используется для пересылки параметра в точности так, как он был передан функции. Как показано здесь:

Когда использовать std :: forward для пересылки аргументов?

Использование std::move предлагает объект в качестве значения r, чтобы, возможно, соответствовать конструктору перемещения или функции, принимающей значения r. Он делает это для std::move(x), даже если x само по себе не является значением.

...