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);
}
void test_std_move2(){
ResHeavy rh; // only one int[]
// operator rh
// after some operator of rh, it becomes no-use
// transform it to other object
ResHeavy rh2 = std::move(rh); // rh becomes invalid
// show rh, rh2 it valid
if(rh.is_up_valid())
cout<<"rh valid"<<endl;
else
cout<<"rh invalid"<<endl;
if(rh2.is_up_valid())
cout<<"rh2 valid"<<endl;
else
cout<<"rh2 invalid"<<endl;
// new ResHeavy object, created by copy ctor
ResHeavy rh3(rh2); // two copy of int[]
if(rh3.is_up_valid())
cout<<"rh3 valid"<<endl;
else
cout<<"rh3 invalid"<<endl;
}
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)`
6 回答
1.“这是什么?”
虽然
std::move()
在技术上是一个功能 - 我会说 it isn't really a function . 它是编译器考虑表达式值的方式之间的转换器 .2.“它做了什么?”
首先要注意的是
std::move()
doesn't actually move anything .如果你曾经看过动画系列Bleach--它相当于Quincy Seele Schneider的Reishi软化 .
但是,严肃地说,它将一个表达式转换为lvalue or pure rvalue(例如你可能已经使用很长一段时间的变量,或者暂时分别传递一段时间)作为xvalue . xvalue告诉编译器:
换句话说,当你使用
std::move(x)
时,你允许编译器蚕食x
. 因此,如果x
在内存中有自己的缓冲区 - 在_444631之后,编译器可以让另一个对象拥有它 .3.“应该何时使用?”
提出这个问题的另一种方法是“我会将现有对象的资源用于什么?”好吧,如果您正在编写应用程序代码,那么您可能不会对编译器创建的临时对象进行大量处理 . 因此,主要是在构造函数,运算符方法,类似STL算法的函数等场合执行此操作,其中对象自动创建和销毁很多 . 当然,这只是一个经验法则 .
典型的用法是从一个对象到另一个对象的资源而不是复制 . @Guillaume链接到this page,它有一个简单的简短例子:用较少的复制交换两个对象 .
使用move允许您交换资源而不是复制它们:
想想当T是大小为n的
vector<int>
时会发生什么 . 在第一个版本中,您读取和写入3 * n个元素,在第二个版本中,您基本上只读取和写入向量缓冲区的3个指针 . 当然,T级需要知道如何进行移动;你应该有一个移动赋值运算符和一个T类的移动构造函数,以便它可以工作 .上面已经解释了 What is it? 和 What does it do? .
我举一个 when it should be used. 的例子
例如,我们有一个包含大数组资源的类 .
测试代码:
输出如下:
我们可以看到
std::move
与move constructor
轻松地生成转换资源 .还有什么地方std :: move有用吗?
std :: move在排序元素数组时也很有用 . 许多排序算法(例如选择排序和冒泡排序)通过交换元素对来工作 . 在之前的版本中,我们不得不求助于复制语义来进行交换 . 现在我们可以使用移动语义,这样更有效 .
如果我们想将一个智能指针管理的内容移动到另一个智能指针,它也会很有用 .
引:
https://www.learncpp.com/cpp-tutorial/15-4-stdmove/
std :: move本身并没有做太多 . 我认为它为对象调用了移动的构造函数,但它实际上只执行了类型转换(将左值变量转换为rvalue,以便所述变量可以作为参数传递给移动构造函数或赋值运算符) .
因此std :: move仅用作使用移动语义的前兆 . 移动语义本质上是处理临时对象的有效方式 .
考虑对象
A = B + C + D + E + F;
这是漂亮的代码,但E F产生一个临时对象 . 然后D temp产生另一个临时对象,依此类推 . 在类的每个普通“”运算符中,都会出现深拷贝 .
例如
在这个函数中创建临时对象是没用的 - 当这些临时对象超出范围时,它们将在行尾删除 .
我们宁愿使用移动语义来“掠夺”临时对象并执行类似的操作
这样可以避免不必要的深拷贝 . 参考该示例,发生深度复制的唯一部分现在是E F.其余部分使用移动语义 . 还需要实现移动构造函数或赋值运算符以将结果分配给A.
当您需要在其他地方“转移”对象的内容时,可以使用move,而无需复制(例如,内容不重复,这就是为什么它可以用在某些不可复制的对象上,如unique_ptr) . 使用std :: move,对象也可以在不进行复制(并节省大量时间)的情况下获取临时对象的内容 .
这个链接真的帮助了我:
http://thbecker.net/articles/rvalue_references/section_01.html
如果我的答案来得太晚,我很抱歉,但我也在寻找std :: move的良好链接,我发现上面的链接有点“严峻” .
这强调了r值参考,在哪种情况下你应该使用它们,我认为它更详细,这就是为什么我想分享这个链接在这里 .
问:什么是std :: move?
答:
std::move()
是C标准库中用于转换为右值引用的函数 .简单地
std::move(t)
相当于:rvalue是一个临时值,它不会超出定义它的表达式,例如从不存储在变量中的中间函数结果 .
std :: move()的实现在N2027: "A Brief Introduction to Rvalue References"中给出,如下所示:
如您所见,无论是使用值(
T
),引用类型(T&
)还是右值引用(T&&
)调用,std::move
都会返回T&&
.问:它做了什么?
答:作为演员,它在运行时没有做任何事情 . 只有在编译时才能告诉编译器您希望继续将引用视为rvalue .
它的作用 not 做:
制作参数的副本
调用复制构造函数
更改参数对象
问:什么时候应该使用?
答:如果要使用不是rvalue(临时表达式)的参数调用支持移动语义的函数,则应使用
std::move
.这为我提出了以下后续问题:
什么是移动语义?与复制语义相比,移动语义是一种编程技术,其中通过“接管”而不是复制另一个对象的成员来初始化对象的成员 . 这种“接管”只能通过指针和资源句柄来实现,可以通过复制指针或整数句柄而不是底层数据来便宜地转移 .
什么样的类和对象支持移动语义?作为开发人员,您可以在自己的类中实现移动语义,如果这些语言将从传输其成员而不是复制它们中受益 . 一旦实现了移动语义,您将直接受益于许多库程序员的工作,他们已经添加了对有效处理具有移动语义的类的支持 .
为什么编译器不能自己搞清楚?除非你这样说,否则编译器不能只调用函数的另一个重载 . 您必须帮助编译器选择是否应该调用常规或移动版本的函数 .
在哪种情况下,我想告诉编译器它应该将变量视为右值?这很可能发生在模板或库函数中,您知道可以挽救中间结果 .
Wikipedia Page on C++11 R-value references and move constructors
在C 11中,除了复制构造函数外,对象还可以有移动构造函数 .
(除了复制赋值运算符,它们还有移动赋值运算符 . )
如果对象的类型为"rvalue-reference"(
Type &&
),则使用移动构造函数而不是复制构造函数 .std::move()
是一个转换器,它生成对象的rvalue引用,以便从中移动 .这是一种避免复制的新方法 . 例如,使用移动构造函数,
std::vector
只能将其内部指针复制到新对象,使移动的对象保持不正确状态,从而避免复制所有数据 . 这将是C-有效 .尝试谷歌搜索移动语义,右值,完美转发 .