В чем разница между std:: move и std:: forward
Я видел это здесь:
Конструктор перемещения вызов базового класса конструктор перемещения
может кто-нибудь объяснить:
- разницу между
std::moveиstd::forward, желательно с примерами кода? - как думать об этом легко, а когда следует использовать
3 ответов:
std::moveпринимает объект и позволяет рассматривать его как временный (rvalue). Хотя это не семантическое требование, обычно функция, принимающая ссылку на rvalue, делает ее недействительной. Когда вы видитеstd::move, это означает, что значение объекта не должно использоваться впоследствии, но вы все равно можете назначить новое значение и продолжить его использование.
std::forwardимеет один вариант использования: чтобы привести шаблонный параметр функции (внутри функции) к категории значений (lvalue или rvalue) вызывающий объект, используемый для его передачи. Это позволяет аргументы rvalue быть принят в качестве правосторонние значения, и значения lvalue быть принят в качестве значения lvalue, схема называется "совершенной прямой."до иллюстрации:
void overloaded( int const &arg ) { std::cout << "by lvalue\n"; } void overloaded( int && arg ) { std::cout << "by rvalue\n"; } template< typename t > /* "t &&" with "t" being template param is special, and adjusts "t" to be (for example) "int &" or non-ref "int" so std::forward knows what to do. */ void forwarding( t && arg ) { std::cout << "via std::forward: "; overloaded( std::forward< t >( arg ) ); std::cout << "via std::move: "; overloaded( std::move( arg ) ); // conceptually this would invalidate arg std::cout << "by simple passing: "; overloaded( arg ); } int main() { std::cout << "initial caller passes rvalue:\n"; forwarding( 5 ); std::cout << "initial caller passes lvalue:\n"; int x = 5; forwarding( x ); }как упоминает Говард, есть также сходства, поскольку обе эти функции просто приводят к ссылочному типу. Но за пределами этих конкретных случаев использования (которые охватывают 99,9% полезности ссылок rvalue) вы должны использовать
static_castнапрямую и написать хорошее объяснение того, что вы делаете.
и
std::forwardиstd::moveне бросает.X x; std::move(x);выше приведено выражение lvalue
xтипа X к выражению rvalue типа X (xvalue, чтобы быть точным).moveтакже может принимать значение rvalue:std::move(make_X());и в этом случае это функция идентификации: принимает rvalue типа X и возвращает rvalue типа X.
С
std::forwardвы можете выбрать пункт назначения в какой-то степени:X x; std::forward<Y>(x);бросает именующее выражение
xтипа X к выражению типа Y. существуют ограничения на то, что Y может быть.Y может быть доступной базой X, или ссылкой на базу X. Y может быть X, или ссылкой на X. нельзя отбрасывать CV-квалификаторы с
forward, но можно добавить cv-квалификаторы. Y не может быть типом, который просто конвертируется из X, за исключением доступного базового преобразования.если Y является ссылкой lvalue, результатом будет выражение lvalue. Если Y не является ссылкой lvalue, результатом будет выражение rvalue (xvalue, чтобы быть точным).
forwardможет принимать аргумент rvalue только в том случае, если Y не является ссылкой lvalue. То есть, вы не можете привести rvalue к lvalue. Это делается по соображениям безопасности, поскольку это обычно приводит к висячим ссылкам. Но приведение rvalue к rvalue в порядке и разрешено.если вы попытаетесь указать Y для чего-то, что не разрешено, ошибка будет поймана во время компиляции, а не запуска время.
std::forwardиспользуется вперед параметр точно так же, как он был передан функции. Как показано здесь:когда использовать аргументы std::forward to forward?
используя
std::moveпредлагает объект в качестве rvalue, чтобы, возможно, соответствовать конструктору перемещения или функции, принимающей rvalues. Он делает это дляstd::move(x)даже еслиxне является rvalue само по себе.
Comments