是什么? 它能做什么? 什么时候使用?
好的链接是赞赏的。
是什么? 它能做什么? 什么时候使用?
好的链接是赞赏的。
当前回答
Std::move本身并没有做很多事情。我以为它调用对象的移动构造函数,但它实际上只是执行类型转换(将左值变量转换为右值,以便所述变量可以作为参数传递给移动构造函数或赋值操作符)。
std::move只是用作move语义的前身。Move语义本质上是处理临时对象的一种有效方法。
考虑对象A = B + (C + (D + (E + F)));
这是一个漂亮的代码,但是E + F生成了一个临时对象。然后D + temp生成另一个临时对象,依此类推。在类的每个普通“+”操作符中,都会发生深度复制。
例如
Object Object::operator+ (const Object& rhs) {
Object temp (*this);
// logic for adding
return temp;
}
在这个函数中创建临时对象是无用的——这些临时对象无论如何都会在行末被删除,因为它们超出了作用域。
我们可以使用move语义来“掠夺”临时对象,并做一些类似的事情
Object& Object::operator+ (Object&& rhs) {
// logic to modify rhs directly
return rhs;
}
这避免了不必要的深度复制。在这个例子中,唯一发生深度复制的部分是E + f,其余部分使用move语义。还需要实现move构造函数或赋值操作符来将结果赋值给A。
其他回答
问:什么是std::move?
答:std::move()是c++标准库中用于强制转换为右值引用的函数。
简单来说,std::move(t)等价于:
static_cast<T&&>(t);
右值是一个临时值,它不会在定义它的表达式之外持久存在,比如一个中间函数结果,它永远不会存储在变量中。
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
std::move()的实现在N2027中给出:“右值引用简介”如下所示:
template <class T>
typename remove_reference<T>::type&&
std::move(T&& a)
{
return a;
}
如你所见,std::move返回T&&,无论调用时使用值(T)、引用类型(T&)或右值引用(T&&)。
问:它能做什么?
答:作为一个强制转换,它在运行时不做任何事情。只有在编译时告诉编译器您希望继续将引用视为右值才有意义。
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)`
它没有做什么:
复制参数 调用复制构造函数 更改参数对象
问:什么时候使用?
答:如果你想调用一个参数不是右值(临时表达式)的支持move语义的函数,应该使用std::move。
这就引出了以下问题:
What is move semantics? Move semantics in contrast to copy semantics is a programming technique in which the members of an 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. 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 the 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 (rather than allocating a new instance).
c++ 11 R-value引用和move构造函数的维基百科页面
在c++ 11中,除了复制构造函数,对象还可以有移动构造函数。 (除了复制赋值操作符,它们还有移动赋值操作符。) 如果对象的类型为“rvalue-reference”(type &&),则使用移动构造函数而不是复制构造函数。 move()是一个强制转换,它产生一个指向对象的右值引用,以实现从对象中移动。
这是一种新的c++避免复制的方法。例如,使用move构造函数,std::vector可以将其指向数据的内部指针复制到新对象,使被移动的对象处于moved from状态,因此不复制所有数据。这将是c++有效的。
试试谷歌一下移动语义,右值,完美转发。
当你需要将一个对象的内容“转移”到其他地方时,你可以使用move,而不需要进行复制(即内容不复制,这就是为什么它可以用于一些不可复制的对象,如unique_ptr)。使用std::move,对象也可以在不复制的情况下获取临时对象的内容(节省大量时间)。
这个链接真的帮了我大忙:
http://thbecker.net/articles/rvalue_references/section_01.html
如果我的回答来得太晚了,我很抱歉,但我也在为std::move寻找一个好的链接,我发现上面的链接有点“严峻”。
这强调了r值引用,在什么情况下你应该使用它们,我认为它更详细,这就是为什么我想在这里分享这个链接。
1. “这是什么?”
虽然std::move()技术上是一个函数-我想说它不是一个真正的函数。它有点像编译器考虑表达式值的方式之间的转换器。
2. “它能做什么?”
首先要注意的是std::move()实际上并不移动任何东西。它将表达式从左值(如命名变量)更改为xvalue。xvalue告诉编译器:
你可以掠夺我,移动我持有的任何东西并在其他地方使用(因为我很快就会被摧毁)”。
换句话说,当你使用std::move(x)时,你是在允许编译器蚕食x。因此,如果x在内存中有自己的缓冲区-在std::move()ing之后,编译器可以让另一个对象拥有它。
您还可以从一个prvalue(例如传递的临时值)中移动,但这很少有用。
3.“什么时候使用?”
问这个问题的另一种方法是“我要为了什么而占用现有对象的资源?”好吧,如果您正在编写应用程序代码,那么您可能不会过多地使用编译器创建的临时对象。主要是在构造函数,操作符方法,标准库算法类函数等地方,在这些地方,对象会自动创建和销毁。当然,这只是一个经验法则。
典型的用法是将资源从一个对象“移动”到另一个对象,而不是复制。@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)
}
使用move可以让你交换资源,而不是复制它们:
template <class T>
swap(T& a, T& b) {
T tmp(std::move(a));
a = std::move(b);
b = std::move(tmp);
}
想想当T是,比如说,向量<int>,大小为n。在第一个版本中,你读写了3*n个元素,在第二个版本中,你基本上只读写了3个指向向量缓冲区的指针,加上3个缓冲区的大小。当然,类T需要知道如何移动;你的类应该有一个移动赋值操作符和一个类T的移动构造函数,这样才能工作。
Std::move本身并没有做很多事情。我以为它调用对象的移动构造函数,但它实际上只是执行类型转换(将左值变量转换为右值,以便所述变量可以作为参数传递给移动构造函数或赋值操作符)。
std::move只是用作move语义的前身。Move语义本质上是处理临时对象的一种有效方法。
考虑对象A = B + (C + (D + (E + F)));
这是一个漂亮的代码,但是E + F生成了一个临时对象。然后D + temp生成另一个临时对象,依此类推。在类的每个普通“+”操作符中,都会发生深度复制。
例如
Object Object::operator+ (const Object& rhs) {
Object temp (*this);
// logic for adding
return temp;
}
在这个函数中创建临时对象是无用的——这些临时对象无论如何都会在行末被删除,因为它们超出了作用域。
我们可以使用move语义来“掠夺”临时对象,并做一些类似的事情
Object& Object::operator+ (Object&& rhs) {
// logic to modify rhs directly
return rhs;
}
这避免了不必要的深度复制。在这个例子中,唯一发生深度复制的部分是E + f,其余部分使用move语义。还需要实现move构造函数或赋值操作符来将结果赋值给A。