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

问题描述 投票:0回答:3

Effective Modern C++ 中的第 29 条,Scott Meyers 列出了移动语义不能提高代码性能的三种场景,

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

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

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

[…]移动语义没有提供效率增益的另一种情况:

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

(第 25 项的标题为 在右值引用上使用

std::move
,在通用引用上使用
std::forward
,但我不明白它与交叉引用它的项目符号点有什么关系。)

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

该要点指的是什么?

据我了解移动语义,即使我想从左值移动,比如

x

,我仍然需要通过
std::move(x)
(或等效的
static_cast
)将其转换为右值,所以我从技术上讲,仍然是从右值(特别是本例中的 x 值),而不是左值开始。

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

我对这个主题缺少什么?

c++ c++11 move-semantics lvalue effective-c++
3个回答
1
投票
术语

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

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


0
投票
HolyBlackCat没看错,答案确实在第25条,接近尾声:

编译器可能会省略本地对象的复制(或移动)[...]

Widget makeWidget() { Widget w; //… return w; }
[…] 每个像样的 C++ 编译器都会使用 RVO 来避免复制 

w

[…]如果满足 RVO 的条件,但编译器选择不执行复制省略,则返回的对象

必须被视为右值。实际上,该标准要求当允许 RVO 时,要么发生复制省略,要么隐式应用 std::move

 […]


-1
投票
举个例子:你有一个带有移动构造函数的类 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);
或返回另一个返回对象的函数的返回值。

© www.soinside.com 2019 - 2024. All rights reserved.