一个C ++接下来的博客文章说,
A compute(…)
{
A v;
…
return v;
}
如果A
具有可访问的复制或移动构造函数,编译器可能选择的Elid到副本。 否则,如果A
有一个移动构造函数, v
是感动。 否则,如果A
有一个拷贝构造函数, v
被复制。 否则,发出一个编译时错误。
我想我应该总是返回值,而不std::move
,因为编译器将能够找出最佳的供用户选择。 但是从博客文章另一个例子
Matrix operator+(Matrix&& temp, Matrix&& y)
{ temp += y; return std::move(temp); }
这里std::move
是必要的,因为y
必须作为函数内的左值来处理。
啊,我的头几乎学习这篇博客后炸毁。 我尽我所能理解,但我学的越多,越糊涂我成了推理。 我们为什么要的帮助下返回值std::move
?
所以,让我们说你有:
A compute()
{
A v;
…
return v;
}
而你正在做的:
A a = compute();
有两种传输(复制或移动)中涉及的这个表达。 首先由表示的对象v
的函数必须被转移到函数的结果,即,由捐赠的值compute()
的表达。 让我们称之为转移。然后,这个临时对象被转移到通过创建代表对象a
-转让2。
在许多情况下,这两个传输1和2可以被编译器消隐-对象v
被直接构建在的位置a
和没有转移是必要的。 编译器必须作出在这个例子中传输1使用命名返回值优化的,因为被返回的对象而得名。 如果我们禁止复制/移动省音,但是,每个转移涉及到任何一个的拷贝构造函数或它的移动构造函数的调用。 在最现代的编译器,编译器会看到v
即将被摧毁,它会首先将其移到返回值。 然后这个临时的返回值将被转移到a
。 如果A
不具有移动构造函数,它会被复制两个转移来。
现在,让我们来看看:
A compute(A&& v)
{
return v;
}
我们返回的值来自参考被传递给函数。 编译器不只是假设, v
是暂时的,这没关系从中1移动。 在这种情况下,转移1将一份副本。 然后换乘2将是一招 - 这没关系,因为返回的值仍然是临时的(我们没有返回引用)。 但是,因为我们知道 ,我们已经采取了对象,我们可以从移动,因为我们的参数是一个右值引用,我们可以明确地告诉编译器把v
作为一个临时std::move
:
A compute(A&& v)
{
return std::move(v);
}
现在,这两个传输1和传输2会移动。
1为什么编译器不会自动把原因v
,定义为A&&
,作为右值是安全的一个。 这不只是太笨了搞清楚。 一旦一个对象都有一个名字,它可以在你的代码被称为多次。 考虑:
A compute(A&& a)
{
doSomething(a);
doSomethingElse(a);
}
如果a
已自动为右值处理, doSomething
就可以自由地撕裂它的胆量了,这意味着a
传递幸福doSomethingElse
可能无效。 即使doSomething
把它的参数通过值,对象将从移动,因此下一行无效。 为了避免这个问题,名为右值引用是左值。 这意味着,当doSomething
叫, a
在最坏的情况从,如果不只是采取左值引用复制的意志-它仍然会在下一行有效。
它是由笔者compute
的说,“好吧,现在我允许从移动这个值,因为我肯定知道这是一个临时的对象”。 你说这样做std::move(a)
。 例如,你可以给doSomething
副本,然后让doSomethingElse
从中移动:
A compute(A&& a)
{
doSomething(a);
doSomethingElse(std::move(a));
}
这些函数结果的隐式的举动,才可能进行自动对象。 右值参考参数不表示自动对象,因此,你必须在这种情况下明确地请求移动。
首先利用NVRO的,比移动的还要好。 没有复制比便宜的好。
第二不能把NVRO的优势。 假设没有省音, return temp;
会调用拷贝构造函数和return std::move(temp);
会叫的移动构造函数。 现在,我相信无论是这些具有相同的潜力,可被忽略,所以你应该用更便宜的一个,如果不是省略掉,这是使用去std::move
。
在C ++ 17和后
C ++ 17变值类的定义,以便复制省略的你所描述的那种保证 (见: ?如何保证复制省略工作 )。 因此,如果你写你的代码在C ++ 17或更高版本,你绝对不应该被返回std::move()
“荷兰国际集团在这种情况下。