是什么? 它能做什么? 什么时候使用?
好的链接是赞赏的。
是什么? 它能做什么? 什么时候使用?
好的链接是赞赏的。
当前回答
当你需要将一个对象的内容“转移”到其他地方时,你可以使用move,而不需要进行复制(即内容不复制,这就是为什么它可以用于一些不可复制的对象,如unique_ptr)。使用std::move,对象也可以在不复制的情况下获取临时对象的内容(节省大量时间)。
这个链接真的帮了我大忙:
http://thbecker.net/articles/rvalue_references/section_01.html
如果我的回答来得太晚了,我很抱歉,但我也在为std::move寻找一个好的链接,我发现上面的链接有点“严峻”。
这强调了r值引用,在什么情况下你应该使用它们,我认为它更详细,这就是为什么我想在这里分享这个链接。
其他回答
下面是一个完整的例子,使用std::move来处理一个(简单的)自定义向量
预期的输出:
c: [10][11]
copy ctor called
copy of c: [10][11]
move ctor called
moved c: [10][11]
编译:
g++ -std=c++2a -O2 -Wall -pedantic foo.cpp
代码:
#include <iostream>
#include <algorithm>
template<class T> class MyVector {
private:
T *data;
size_t maxlen;
size_t currlen;
public:
MyVector<T> () : data (nullptr), maxlen(0), currlen(0) { }
MyVector<T> (int maxlen) : data (new T [maxlen]), maxlen(maxlen), currlen(0) { }
MyVector<T> (const MyVector& o) {
std::cout << "copy ctor called" << std::endl;
data = new T [o.maxlen];
maxlen = o.maxlen;
currlen = o.currlen;
std::copy(o.data, o.data + o.maxlen, data);
}
MyVector<T> (const MyVector<T>&& o) {
std::cout << "move ctor called" << std::endl;
data = o.data;
maxlen = o.maxlen;
currlen = o.currlen;
}
void push_back (const T& i) {
if (currlen >= maxlen) {
maxlen *= 2;
auto newdata = new T [maxlen];
std::copy(data, data + currlen, newdata);
if (data) {
delete[] data;
}
data = newdata;
}
data[currlen++] = i;
}
friend std::ostream& operator<<(std::ostream &os, const MyVector<T>& o) {
auto s = o.data;
auto e = o.data + o.currlen;;
while (s < e) {
os << "[" << *s << "]";
s++;
}
return os;
}
};
int main() {
auto c = new MyVector<int>(1);
c->push_back(10);
c->push_back(11);
std::cout << "c: " << *c << std::endl;
auto d = *c;
std::cout << "copy of c: " << d << std::endl;
auto e = std::move(*c);
delete c;
std::cout << "moved c: " << e << std::endl;
}
c++ 11 R-value引用和move构造函数的维基百科页面
在c++ 11中,除了复制构造函数,对象还可以有移动构造函数。 (除了复制赋值操作符,它们还有移动赋值操作符。) 如果对象的类型为“rvalue-reference”(type &&),则使用移动构造函数而不是复制构造函数。 move()是一个强制转换,它产生一个指向对象的右值引用,以实现从对象中移动。
这是一种新的c++避免复制的方法。例如,使用move构造函数,std::vector可以将其指向数据的内部指针复制到新对象,使被移动的对象处于moved from状态,因此不复制所有数据。这将是c++有效的。
试试谷歌一下移动语义,右值,完美转发。
Std::move本身除了static_cast之外什么也不做。根据cppreference.com网站
它完全等价于static_cast到右值引用类型。
因此,它取决于你在移动后赋值给的变量的类型,如果该类型具有接受右值形参的构造函数或赋值操作符,它可能会或可能不会窃取原始变量的内容,因此,它可能会让原始变量处于未指定的状态:
除非另有说明,否则所有移出的标准库对象都处于有效但未指定的状态。
因为对于内置文字类型(如整数和原始指针)没有特殊的移动构造函数或移动赋值操作符,因此,它将只是对这些类型进行简单的复制。
当你需要将一个对象的内容“转移”到其他地方时,你可以使用move,而不需要进行复制(即内容不复制,这就是为什么它可以用于一些不可复制的对象,如unique_ptr)。使用std::move,对象也可以在不复制的情况下获取临时对象的内容(节省大量时间)。
这个链接真的帮了我大忙:
http://thbecker.net/articles/rvalue_references/section_01.html
如果我的回答来得太晚了,我很抱歉,但我也在为std::move寻找一个好的链接,我发现上面的链接有点“严峻”。
这强调了r值引用,在什么情况下你应该使用它们,我认为它更详细,这就是为什么我想在这里分享这个链接。
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。