什么是std: move(),什么时候使用?

时间:2022-09-10 23:48:41
  1. What is it?
  2. 它是什么?
  3. What does it do?
  4. 它做什么?
  5. When should it be used?
  6. 什么时候使用?

Good links are appreciated.

良好的链接是感激。

5 个解决方案

#1


177  

http://en.wikipedia.org/wiki/C%2B%2B11#Rvalue_references_and_move_constructors
http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2006/n2027.html#Move_Semantics

http://en.wikipedia.org/wiki/C%2B%2B11 Rvalue_references_and_move_constructors http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2006/n2027.html Move_Semantics

  1. In C++11, in addition to copy constructors, objects can have move constructors.
    (And in addition to copy assignment operators, they have move assignment operators.)
  2. 在c++ 11中,除了复制构造函数之外,对象还可以有move构造函数。(除了复制赋值操作符,他们还有移动赋值操作符。)
  3. The move constructor is used instead of the copy constructor, if the object has type "rvalue-reference" (Type &&).
  4. 如果对象具有类型“rvalue-reference”(类型&&),则使用move构造函数代替复制构造函数。
  5. std::move() is a cast that produces an rvalue-reference to an object, to enable moving from it.
  6. move()是一个类型转换,它生成一个对象的rvalue-reference,以便从对象中移动。

It's a new C++ way to avoid copies. For example, using a move constructor, a std::vector could just copy its internal pointer to data to the new object, leaving the moved object in an incorrect state, avoiding to copy all data. This would be C++-valid.

这是一种新的c++避免拷贝的方法。例如,使用move构造函数,std::vector可以将它的内部指针复制到新对象,使被移动的对象处于不正确的状态,避免复制所有数据。这将是c++有效。

Try googling for move semantics, rvalue, perfect forwarding.

尝试搜索移动语义、rvalue、完美转发。

#2


113  

You can use move when you need to "transfer" the content of an object somewhere else, without doing a copy (e.g the content is not duplicated, that's why it could be use on some non-copyable objects, like an unique_ptr). It's also possible for an object to take the content of a temporary object without doing a copy (and save a lot of time), with std::move.

当您需要“传输”对象的内容时,您可以使用move,而不需要进行复制(e)。g内容没有重复,这就是为什么它可以用于一些不可复制的对象,比如unique_ptr)。对于一个对象来说,如果不执行复制(并节省大量时间),对象就可以获取一个临时对象的内容,而std::move。

This link really helped me out :

这个链接真的帮了我:

http://thbecker.net/articles/rvalue_references/section_01.html

http://thbecker.net/articles/rvalue_references/section_01.html

I'm sorry if my answer is coming too late, but I was also looking for a good link for the std::move, and I found the links above a little bit "austere".

如果我的答案来得太晚了,我很抱歉,但我也在为std::move寻找一个好的链接,我发现上面的链接有点“简单”。

This put the emphasis on r-value reference, in which context you should use them, and I think it's more detailed, that's why I wanted to share this link here.

这强调了r-value引用,在这种情况下你应该使用它们,我认为它更详细,这就是为什么我想在这里分享这个链接。

#3


86  

1. "What is it?"

While std::move() "looks like" a function - I would say it isn't really a function. It's sort of a converter between ways the compiler considers an expression's value.

而std::移动()看起来像一个函数,我想说它不是一个函数。它是编译器考虑表达式值的方式之间的一种转换。

2. "What does it do?"

The first thing to note is that std::move() doesn't actually move anything.

首先要注意的是std::move()实际上不会移动任何东西。

If you've ever watched the animation series Bleach - it does the equivalent of Quincy Seele Schneider's Reishi softening (see also its use in this scene).

如果你看过动画系列的漂白剂——它相当于Quincy Seele Schneider的Reishi软化(见它在这个场景中的使用)。

Seriously, though, it converts an expression from being an lvalue or pure rvalue (such as a variable you might be using for a long time yet, or a temporary you're passing around for a while, respectively) to being an xvalue. An xvalue tells the compiler:

不过,认真地说,它将表达式从lvalue或纯rvalue(例如,您可能已经使用了很长时间的变量,或者是您分别传递了一段时间的临时变量)转换为xvalue。一个xvalue告诉编译器:

You can plunder me, move anything I'm holding and use it elsewhere (since I'm going to be destroyed soon anyway)".

你可以掠夺我,移动我持有的任何东西,然后把它用在别的地方(反正我很快就会被毁灭)。

in other words, when you use std::move(x), you're allowing the compiler to cannibalize x. Thus if x has, say, its own buffer in memory - after std::move()ing the compiler can have another object own it instead.

换句话说,当您使用std::move(x)时,您允许编译器对x进行分区,因此,如果x在内存中有自己的缓冲区——在std::move()之后,编译器就可以拥有另一个对象了。

3. "When should it be used?"

Another way to ask this question is "What would I use/cannibalize an object's resources for?" well, if you're writing application code, you would probably not be messing around a lot with temporary objects created by the compiler. So mainly you would do this in places like constructors, operator methods, STL-algorithm-like functions etc. where objects get created and destroyed automagically alot. Of course, that's just a rule of thumb.

问这个问题的另一种方式是“我将使用/占用一个对象的资源做什么?”所以你主要会在构造函数,运算符方法,stl算法之类的函数中这样做,在这些函数中对象会自动被创建和销毁。当然,这只是经验之谈。

A typical use is 'moving' resources from one object to another instead of copying. @Guillaume links to this page which has a straightforward short example: swapping two objects with less copying.

一个典型的用法是将资源从一个对象“移动”到另一个对象,而不是复制。@Guillaume链接到这个页面,它有一个简单的简短示例:用较少的拷贝交换两个对象。

template <class T>
swap(T& a, T& b) {
    T tmp(a);   // we now have two copies of a
    a = b;      // we now have two copies of b (+ discarded a copy of a)
    b = tmp;    // we now have two copies of tmp (+ discarded a copy of b)
}

using move allows you to swap the resources instead of copying them around:

使用move允许您交换资源,而不是复制它们:

template <class T>
swap(T& a, T& b) {
    T tmp(std::move(a));
    a = std::move(b);   
    b = std::move(tmp);
}

Think of what happens when T is, say, vector<int> of size n. In the first version you read and write 3*n elements, in the second version you basically read and write just the 3 pointers to the vectors' buffers. Of course, class T needs to know how to do the moving; you should have a move-assignment operator and a move-constructor for class T for this to work.

想想当T是,向量 ,大小为n,在第一个版本中,你读和写了3*n个元素,在第二个版本中,你基本上只读和写了向量缓冲区的3个指针。当然,T类需要知道如何移动;你应该有一个动作赋值运算符和一个动作构造函数,用于类T。

#4


24  

std::move itself doesn't really do much. I thought that it called the moved constructor for an object, but it really just performs a type cast (casting an lvalue variable to an rvalue so that the said variable can be passed as an argument to a move constructor or assignment operator).

移动本身并没有多大作用。我认为它为一个对象调用了移动的构造函数,但它实际上只是执行一个类型转换(将一个lvalue变量转换为一个rvalue,以便将所述变量作为参数传递给移动构造函数或赋值操作符)。

So std::move is just used as a precursor to using move semantics. Move semantics is essentially an efficient way for dealing with temporary objects.

所以std::move只是用作使用move语义的前兆。移动语义本质上是处理临时对象的一种有效方法。

Consider Object A = B + C + D + E + F;

考虑对象A = B + C + D + E + F;

This is nice looking code, but E + F produces a temporary object. Then D + temp produces another temporary object and so on. In each normal "+" operator of a class, deep copies occur.

这段代码看起来不错,但是E + F生成一个临时对象。然后D + temp生成另一个临时对象等等。在类的每个正常的“+”操作符中,都会发生深度拷贝。

For example

例如

Object Object::operator+ (const Object& rhs) {
    Object temp (*this);
    // logic for adding
    return temp;
}

The creation of the temporary object in this function is useless - these temporary objects will be deleted at the end of the line anyway as they go out of scope.

在此函数中创建临时对象是无用的——这些临时对象在超出范围时将在行尾被删除。

We can rather use move semantics to "plunder" the temporary objects and do something like

我们可以使用移动语义来“掠夺”临时对象,并做类似的事情

 Object& Object::operator+ (Object&& rhs) {
     // logic to modify rhs directly
     return rhs;
 }

This avoid needless deep copies being made. With reference to the example, the only part where deep copying occurs is now E + F. The rest uses move semantics. The move constructor or assignment operator also needs to be implemented to assign the result to A.

这样可以避免不必要的深度拷贝。参考示例,深度复制的惟一部分现在是E + f,其余部分使用移动语义。还需要实现move构造函数或赋值操作符来将结果分配给A。

#5


19  

Q: What is std::move?

A: std::move() is a function from the C++ Standard Library for casting to a rvalue reference.

move()是从c++标准库中转换到rvalue引用的函数。

Simplisticly std::move(t) is equivalent to:

简单的std::move(t)等于:

static_cast<T&&>(t);

An rvalue is a temporary that does not persist beyond the expression that defines it, such as a intermediate function result which is never stored in a variable.

rvalue是一种暂时的,它不会持续到定义它的表达式之外,比如一个中间函数结果,它永远不会存储在变量中。

int a = 3; // 3 is a rvalue, does not exist after expression is evaluated
int b = a; // a is a lvalue, keeps existing after expression is evaluated

An implementation for std::move() is given in N2027: "A Brief Introduction to Rvalue References" as follows:

std::move()的实现在N2027中给出:“Rvalue引用的简要介绍”如下:

template <class T>
typename remove_reference<T>::type&&
std::move(T&& a)
{
    return a;
}

As you can see, std::move returns T&& no matter if called with a value (T), reference type (T&) or rvalue reference (T&&).

如您所见,std::move返回T&& &无论是否调用值(T)、引用类型(t&)或rvalue引用(T&&)。

Q: What does it do?

A: As a cast, it does not do anything during runtime. It is only relevant at compile time to tell the compiler that you would like to continue considering the reference as an rvalue.

答:作为cast,它在运行时不做任何事情。只有在编译时,才需要告诉编译器您希望继续将引用视为rvalue。

foo(3 * 5); // obviously, you are calling foo with a temporary (rvalue)

int a = 3 * 5;
foo(a);     // how to tell the compiler to treat `a` as an rvalue?
foo(std::move(a)); // will call `foo(int&& a)` rather than `foo(int a)` or `foo(int& a)`

What it does not do:

它没有做什么:

  • Make a copy of the argument
  • 把论点复制一份。
  • Call the copy constructor
  • 调用拷贝构造函数
  • Change the argument object
  • 更改参数对象

Q: When should it be used?

A: You should use std::move if you want to call functions which support move semantics with an argument which is not an rvalue (temporary expression).

如果您想调用支持移动语义的函数,您应该使用std::move,它的参数不是rvalue(临时表达式)。

This begs the following follow-up questions for me:

这就引出了以下问题:

  • What are move semantics? Move semantics in contrast to copy semantics is a programming technique in which the members of a object are initialized by 'taking over' instead of copying another object's members. Such 'take over' makes only sense with pointers and resource handles, which can be cheaply transferred by copying the pointer or integer handle rather than the underlying data.

    将语义是什么?与复制语义相反,移动语义是一种编程技术,对象的成员通过“接管”而不是复制其他对象的成员来初始化。这种“接管”只适用于指针和资源句柄,通过复制指针或整数句柄(而不是底层数据)可以廉价地转移它们。

  • What kind of classes and objects support move semantics? It is up to you as a developer to implement move semantics in your own classes if these would benefit from transferring their members instead of copying them. Once you implement move semantics, you will directly benefit from work from many library programmers who have added support for handling classes with move semantics efficiently.

    什么样的类和对象支持移动语义?作为开发人员,您可以在自己的类中实现move语义,如果这些语义可以从转移成员而不是复制成员中获益的话。一旦实现了move语义,您将直接受益于许多库程序员的工作,他们添加了对使用move语义有效地处理类的支持。

  • Why can't the compiler figure it out on its own? The compiler cannot just call another overload of a function unless you say so. You must help the compiler choose whether the regular or move version of function should be called.

    为什么编译器不能自己算出来呢?编译器不能只调用函数的另一个重载,除非你这么说。您必须帮助编译器选择应该调用函数的常规版本还是移动版本。

  • In which situations would I want to tell the compiler that it should treat a variable as an rvalue? This will most likely happen in template or library functions, where you know that an intermediate result could be salvaged.

    在什么情况下我想告诉编译器它应该把变量当作rvalue?这很可能发生在模板或库函数中,您知道中间结果可以被回收。

#1


177  

http://en.wikipedia.org/wiki/C%2B%2B11#Rvalue_references_and_move_constructors
http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2006/n2027.html#Move_Semantics

http://en.wikipedia.org/wiki/C%2B%2B11 Rvalue_references_and_move_constructors http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2006/n2027.html Move_Semantics

  1. In C++11, in addition to copy constructors, objects can have move constructors.
    (And in addition to copy assignment operators, they have move assignment operators.)
  2. 在c++ 11中,除了复制构造函数之外,对象还可以有move构造函数。(除了复制赋值操作符,他们还有移动赋值操作符。)
  3. The move constructor is used instead of the copy constructor, if the object has type "rvalue-reference" (Type &&).
  4. 如果对象具有类型“rvalue-reference”(类型&&),则使用move构造函数代替复制构造函数。
  5. std::move() is a cast that produces an rvalue-reference to an object, to enable moving from it.
  6. move()是一个类型转换,它生成一个对象的rvalue-reference,以便从对象中移动。

It's a new C++ way to avoid copies. For example, using a move constructor, a std::vector could just copy its internal pointer to data to the new object, leaving the moved object in an incorrect state, avoiding to copy all data. This would be C++-valid.

这是一种新的c++避免拷贝的方法。例如,使用move构造函数,std::vector可以将它的内部指针复制到新对象,使被移动的对象处于不正确的状态,避免复制所有数据。这将是c++有效。

Try googling for move semantics, rvalue, perfect forwarding.

尝试搜索移动语义、rvalue、完美转发。

#2


113  

You can use move when you need to "transfer" the content of an object somewhere else, without doing a copy (e.g the content is not duplicated, that's why it could be use on some non-copyable objects, like an unique_ptr). It's also possible for an object to take the content of a temporary object without doing a copy (and save a lot of time), with std::move.

当您需要“传输”对象的内容时,您可以使用move,而不需要进行复制(e)。g内容没有重复,这就是为什么它可以用于一些不可复制的对象,比如unique_ptr)。对于一个对象来说,如果不执行复制(并节省大量时间),对象就可以获取一个临时对象的内容,而std::move。

This link really helped me out :

这个链接真的帮了我:

http://thbecker.net/articles/rvalue_references/section_01.html

http://thbecker.net/articles/rvalue_references/section_01.html

I'm sorry if my answer is coming too late, but I was also looking for a good link for the std::move, and I found the links above a little bit "austere".

如果我的答案来得太晚了,我很抱歉,但我也在为std::move寻找一个好的链接,我发现上面的链接有点“简单”。

This put the emphasis on r-value reference, in which context you should use them, and I think it's more detailed, that's why I wanted to share this link here.

这强调了r-value引用,在这种情况下你应该使用它们,我认为它更详细,这就是为什么我想在这里分享这个链接。

#3


86  

1. "What is it?"

While std::move() "looks like" a function - I would say it isn't really a function. It's sort of a converter between ways the compiler considers an expression's value.

而std::移动()看起来像一个函数,我想说它不是一个函数。它是编译器考虑表达式值的方式之间的一种转换。

2. "What does it do?"

The first thing to note is that std::move() doesn't actually move anything.

首先要注意的是std::move()实际上不会移动任何东西。

If you've ever watched the animation series Bleach - it does the equivalent of Quincy Seele Schneider's Reishi softening (see also its use in this scene).

如果你看过动画系列的漂白剂——它相当于Quincy Seele Schneider的Reishi软化(见它在这个场景中的使用)。

Seriously, though, it converts an expression from being an lvalue or pure rvalue (such as a variable you might be using for a long time yet, or a temporary you're passing around for a while, respectively) to being an xvalue. An xvalue tells the compiler:

不过,认真地说,它将表达式从lvalue或纯rvalue(例如,您可能已经使用了很长时间的变量,或者是您分别传递了一段时间的临时变量)转换为xvalue。一个xvalue告诉编译器:

You can plunder me, move anything I'm holding and use it elsewhere (since I'm going to be destroyed soon anyway)".

你可以掠夺我,移动我持有的任何东西,然后把它用在别的地方(反正我很快就会被毁灭)。

in other words, when you use std::move(x), you're allowing the compiler to cannibalize x. Thus if x has, say, its own buffer in memory - after std::move()ing the compiler can have another object own it instead.

换句话说,当您使用std::move(x)时,您允许编译器对x进行分区,因此,如果x在内存中有自己的缓冲区——在std::move()之后,编译器就可以拥有另一个对象了。

3. "When should it be used?"

Another way to ask this question is "What would I use/cannibalize an object's resources for?" well, if you're writing application code, you would probably not be messing around a lot with temporary objects created by the compiler. So mainly you would do this in places like constructors, operator methods, STL-algorithm-like functions etc. where objects get created and destroyed automagically alot. Of course, that's just a rule of thumb.

问这个问题的另一种方式是“我将使用/占用一个对象的资源做什么?”所以你主要会在构造函数,运算符方法,stl算法之类的函数中这样做,在这些函数中对象会自动被创建和销毁。当然,这只是经验之谈。

A typical use is 'moving' resources from one object to another instead of copying. @Guillaume links to this page which has a straightforward short example: swapping two objects with less copying.

一个典型的用法是将资源从一个对象“移动”到另一个对象,而不是复制。@Guillaume链接到这个页面,它有一个简单的简短示例:用较少的拷贝交换两个对象。

template <class T>
swap(T& a, T& b) {
    T tmp(a);   // we now have two copies of a
    a = b;      // we now have two copies of b (+ discarded a copy of a)
    b = tmp;    // we now have two copies of tmp (+ discarded a copy of b)
}

using move allows you to swap the resources instead of copying them around:

使用move允许您交换资源,而不是复制它们:

template <class T>
swap(T& a, T& b) {
    T tmp(std::move(a));
    a = std::move(b);   
    b = std::move(tmp);
}

Think of what happens when T is, say, vector<int> of size n. In the first version you read and write 3*n elements, in the second version you basically read and write just the 3 pointers to the vectors' buffers. Of course, class T needs to know how to do the moving; you should have a move-assignment operator and a move-constructor for class T for this to work.

想想当T是,向量 ,大小为n,在第一个版本中,你读和写了3*n个元素,在第二个版本中,你基本上只读和写了向量缓冲区的3个指针。当然,T类需要知道如何移动;你应该有一个动作赋值运算符和一个动作构造函数,用于类T。

#4


24  

std::move itself doesn't really do much. I thought that it called the moved constructor for an object, but it really just performs a type cast (casting an lvalue variable to an rvalue so that the said variable can be passed as an argument to a move constructor or assignment operator).

移动本身并没有多大作用。我认为它为一个对象调用了移动的构造函数,但它实际上只是执行一个类型转换(将一个lvalue变量转换为一个rvalue,以便将所述变量作为参数传递给移动构造函数或赋值操作符)。

So std::move is just used as a precursor to using move semantics. Move semantics is essentially an efficient way for dealing with temporary objects.

所以std::move只是用作使用move语义的前兆。移动语义本质上是处理临时对象的一种有效方法。

Consider Object A = B + C + D + E + F;

考虑对象A = B + C + D + E + F;

This is nice looking code, but E + F produces a temporary object. Then D + temp produces another temporary object and so on. In each normal "+" operator of a class, deep copies occur.

这段代码看起来不错,但是E + F生成一个临时对象。然后D + temp生成另一个临时对象等等。在类的每个正常的“+”操作符中,都会发生深度拷贝。

For example

例如

Object Object::operator+ (const Object& rhs) {
    Object temp (*this);
    // logic for adding
    return temp;
}

The creation of the temporary object in this function is useless - these temporary objects will be deleted at the end of the line anyway as they go out of scope.

在此函数中创建临时对象是无用的——这些临时对象在超出范围时将在行尾被删除。

We can rather use move semantics to "plunder" the temporary objects and do something like

我们可以使用移动语义来“掠夺”临时对象,并做类似的事情

 Object& Object::operator+ (Object&& rhs) {
     // logic to modify rhs directly
     return rhs;
 }

This avoid needless deep copies being made. With reference to the example, the only part where deep copying occurs is now E + F. The rest uses move semantics. The move constructor or assignment operator also needs to be implemented to assign the result to A.

这样可以避免不必要的深度拷贝。参考示例,深度复制的惟一部分现在是E + f,其余部分使用移动语义。还需要实现move构造函数或赋值操作符来将结果分配给A。

#5


19  

Q: What is std::move?

A: std::move() is a function from the C++ Standard Library for casting to a rvalue reference.

move()是从c++标准库中转换到rvalue引用的函数。

Simplisticly std::move(t) is equivalent to:

简单的std::move(t)等于:

static_cast<T&&>(t);

An rvalue is a temporary that does not persist beyond the expression that defines it, such as a intermediate function result which is never stored in a variable.

rvalue是一种暂时的,它不会持续到定义它的表达式之外,比如一个中间函数结果,它永远不会存储在变量中。

int a = 3; // 3 is a rvalue, does not exist after expression is evaluated
int b = a; // a is a lvalue, keeps existing after expression is evaluated

An implementation for std::move() is given in N2027: "A Brief Introduction to Rvalue References" as follows:

std::move()的实现在N2027中给出:“Rvalue引用的简要介绍”如下:

template <class T>
typename remove_reference<T>::type&&
std::move(T&& a)
{
    return a;
}

As you can see, std::move returns T&& no matter if called with a value (T), reference type (T&) or rvalue reference (T&&).

如您所见,std::move返回T&& &无论是否调用值(T)、引用类型(t&)或rvalue引用(T&&)。

Q: What does it do?

A: As a cast, it does not do anything during runtime. It is only relevant at compile time to tell the compiler that you would like to continue considering the reference as an rvalue.

答:作为cast,它在运行时不做任何事情。只有在编译时,才需要告诉编译器您希望继续将引用视为rvalue。

foo(3 * 5); // obviously, you are calling foo with a temporary (rvalue)

int a = 3 * 5;
foo(a);     // how to tell the compiler to treat `a` as an rvalue?
foo(std::move(a)); // will call `foo(int&& a)` rather than `foo(int a)` or `foo(int& a)`

What it does not do:

它没有做什么:

  • Make a copy of the argument
  • 把论点复制一份。
  • Call the copy constructor
  • 调用拷贝构造函数
  • Change the argument object
  • 更改参数对象

Q: When should it be used?

A: You should use std::move if you want to call functions which support move semantics with an argument which is not an rvalue (temporary expression).

如果您想调用支持移动语义的函数,您应该使用std::move,它的参数不是rvalue(临时表达式)。

This begs the following follow-up questions for me:

这就引出了以下问题:

  • What are move semantics? Move semantics in contrast to copy semantics is a programming technique in which the members of a object are initialized by 'taking over' instead of copying another object's members. Such 'take over' makes only sense with pointers and resource handles, which can be cheaply transferred by copying the pointer or integer handle rather than the underlying data.

    将语义是什么?与复制语义相反,移动语义是一种编程技术,对象的成员通过“接管”而不是复制其他对象的成员来初始化。这种“接管”只适用于指针和资源句柄,通过复制指针或整数句柄(而不是底层数据)可以廉价地转移它们。

  • What kind of classes and objects support move semantics? It is up to you as a developer to implement move semantics in your own classes if these would benefit from transferring their members instead of copying them. Once you implement move semantics, you will directly benefit from work from many library programmers who have added support for handling classes with move semantics efficiently.

    什么样的类和对象支持移动语义?作为开发人员,您可以在自己的类中实现move语义,如果这些语义可以从转移成员而不是复制成员中获益的话。一旦实现了move语义,您将直接受益于许多库程序员的工作,他们添加了对使用move语义有效地处理类的支持。

  • Why can't the compiler figure it out on its own? The compiler cannot just call another overload of a function unless you say so. You must help the compiler choose whether the regular or move version of function should be called.

    为什么编译器不能自己算出来呢?编译器不能只调用函数的另一个重载,除非你这么说。您必须帮助编译器选择应该调用函数的常规版本还是移动版本。

  • In which situations would I want to tell the compiler that it should treat a variable as an rvalue? This will most likely happen in template or library functions, where you know that an intermediate result could be salvaged.

    在什么情况下我想告诉编译器它应该把变量当作rvalue?这很可能发生在模板或库函数中,您知道中间结果可以被回收。