EMC++中提到的“源对象是左值”情形是什么,在这种情形下,移动语义无法提高效率

rqenqsqc  于 9个月前  发布在  其他
关注(0)|答案(3)|浏览(85)

Effective Modern C++的第29条,Scott Meyers列出了三种移动语义不能提高代码性能的情况,
[...]移动语义学对你没有好处:

***无移动操作:**要移动的对象无法提供移动操作[...]
*移动不快:[...]移动操作不快于其复制操作。
***Move不可用:**上下文[...]需要一个不发出异常的移动操作,但该操作未声明为noexcept

在前面的几页中都有清楚的解释,然后又增加了一个
[...]另一个场景中,移动语义没有提供效率增益:

***Source object is lvalue:**除了极少数的例外情况(参见第25条),只有右值可以用作移动操作的源。

(Item 25的标题是 * 在右值引用上使用std::move,在通用引用上使用std::forward *,但我看不出它与交叉引用它的要点有什么关系。
在此之后,案文基本上回到概述该项目,没有进一步提到第四个要点。
那个要点指的是什么?
就我对移动语义的理解而言,即使我想从左值移动,比如x,我仍然需要通过std::move(x)(或等效的static_cast)将其转换为右值,所以从技术上讲,我仍然是从右值(在这种情况下特别是x值)移动,而不是左值。
所以我想说左值不能作为移动操作的源对象。
关于这个主题,我错过了什么?

ef1yzkbh

ef1yzkbh1#

术语 lvalue 指的是以某种方式命名的值,即有多个引用的实体。移动语义并不真正适用于它们,因为你不应该“窃取”可能在其他地方引用的东西的表示。也就是说,如果源对象是一个左值,你就永远不会移动!所以,移动构造在这里并没有提供好处。事实上,左值并不愿意绑定到右值引用-你需要强制绑定,例如,通过使用std::move()
从本质上讲,你的观点是完全正确的:左值不可能是移动操作的源-因此移动操作在涉及左值的情况下不会提供好处。

c9x0cxw0

c9x0cxw02#

黑猫圣果然没有看错,答案就在第25项的末尾:
编译器可以省略复制(或移动)本地对象[...]

Widget makeWidget() {
  Widget w;
  //…
  return w;
}

字符串
[...]每一个像样的C++编译器都会使用RVO来避免复制w
[...]如果满足RVO的条件,但编译器选择不执行复制省略,则返回的对象 * 必须被视为右值 *。实际上,标准要求当RVO被允许时,要么发生复制省略,要么隐式应用std::move [...]

wgmfuz8q

wgmfuz8q3#

例如:你有一个带有移动构造函数的类T。你有一个返回类型为T的对象的函数,你试图通过返回r值来使它更快。现在,如果你从

T x;
x.a = ...;
x.b = ...;
x.c = ...;
return x;

字符串
然后构造一个对象x,一个新的未命名的对象将由return语句创建,然后x被析构,然后返回值被移动。最后调用者将为移动的结果调用析构函数。所以你有两个构造函数,两个析构函数,没有保存。
如果你开始与

T x(a, b, c);
return x;


那么你有同样的问题,两个构造函数和析构函数,没有保存。要真正保存任何东西,你需要写

return T(a, b, c);


或者返回另一个返回对象的函数的返回值。

相关问题