微信公众号搜"智元新知"关注
微信扫一扫可直接关注哦!

什么是EMC++中提到的“源对象是左值”场景,其中移动语义没有提供效率增益

如何解决什么是EMC++中提到的“源对象是左值”场景,其中移动语义没有提供效率增益

来自 Effective Modern C++ 的第 29 项,Scott Meyers 列出了移动语义不会提高代码性能的三个场景,

[…] 移动语义对你没有好处:

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

前面几页都解释清楚了,再补充一个

[…] 移动语义无法提高效率的另一种情况:

  • 源对象是左值:除了极少数例外(参见例如第 25 条),只有右值可以用作移动操作的源。

(第 25 条的标题在右值引用上使用 std::move,在通用引用上使用 std::forward,但我不明白它与交叉的项目符号有什么关系-引用它。)

在此之后,文本基本上回到了对项目的总结,不再进一步提及第四个要点。

那个要点是指什么?

据我了解移动语义,即使我想从左值移动,比如 x,我仍然需要通过 std::move(x)(或等效的 static_cast 将它转换为右值}}),所以我在技术上仍然是从右值(在这种情况下特别是 xvalue)而不是左值。

所以我很想说左值不能作为移动操作的源对象。

我对这个主题遗漏了什么?

解决方法

术语 lvalue 以某种方式指代“命名”值,即具有多个引用的实体。移动语义并不真正适用于它们,因为您不应该“窃取”可能在其他地方引用的事物的表示。也就是说,如果源对象是左值,您就永远不会移动!因此,移动构造在这里没有任何好处。事实上,左值不会随意绑定到右值引用——你必须强制绑定,例如,通过使用 std::move()

从本质上讲,您的观点完全正确:左值不能作为移动操作的来源 - 因此移动操作在涉及左值的情况下不会提供任何好处。

,

举个例子:你有一个带有移动构造函数的类 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,c);

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

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。