返回本地变量的std::move

3

假设有一个带有移动构造函数的类 A,考虑以下情况:

A get()
{
    A a;
    return std::move( a );
}

// later in the code
A aa = get();

在这里,显式调用 std::move 强制调用 A 的移动构造函数,因此可能会抑制在调用 get() 时的返回值优化。因此,更好的 get() 实现应该是这样的:

A get()
{
    A a;
    return a;
}

但是返回值优化不是C++11标准的一部分,所以如果编译器由于某种原因决定在调用get()时不执行返回值优化,在这种情况下会在get()中返回A的复制构造函数对吗?

那么第一个get()实现不是更可取吗?


3
假如你的编译器决定在每个函数调用前插入一百万个空指令,那该怎么办?你必须选择好你的工具...... 而RVO确实是标准的一个明确部分,只是它并非强制性的。 - Kerrek SB
4
不需要使用 std::move。如果可访问,则会通过 12.8/32 调用 A 的移动构造函数。 - MWid
3
是的,这是一个两阶段的过载解析。首先,返回的对象被视为rvalue进行解析。如果在此情况下解析失败,则将其视为lvalue来处理。关键点在于,返回对象的类型与函数的返回类型相同。 - MWid
3
如果你返回的对象类型是A,但函数的返回类型应该是B,而且B有一个移动构造函数需要一个A作为参数,那么如果你想使用移动语义,就必须显式地写出move - MWid
2
只有一个额外的注意事项:如果移动构造函数是私有或已删除,则无论复制构造函数是公共还是私有,代码都不会编译。 - MWid
显示剩余4条评论
1个回答

3
一款编译器应该使用移动构造函数,但是我没有在标准中看到有这种义务:在涉及临时对象的部分中,总是说“复制/移动构造函数”。
C++的ISO/IEC 14882:2011标准:
“12.1/9” 复制构造函数(12.8)用于复制类类型的对象。移动构造函数(12.8)用于移动类类型对象的内容。
“12.8/32” 当满足复制操作的省略条件或者除了源对象是函数参数外,将要满足省略条件,��且被复制的对象是一个左值时,并通过重载解决选择复制的构造函数。如果重载解析失败或者选定构造函数的第一个参数类型不是指向对象类型(可以是cv限定符)的右值引用,则再次执行重载解析,将对象视为左值。[注意:无论是否进行复制省略,都必须执行此两阶段重载解析。它确定要调用的构造函数(如果未执行省略),并且即使调用被省略,所选的构造函数也必须可访问。 ———结束说明]
“lvalue”= T&; “rvalue”= T&&;
因此,它表示首先编译器会查找移动构造函数,然后查找复制构造函数。
因此,如果您的编译器符合标准,它将调用移动构造函数。
我附加了一些有趣的内容:
“12.8/31” 当满足某些条件时,即使类对象的复制/移动构造函数和/或析构函数具有副作用,实现也可以省略此类对象的复制/移动构造。
因此,即使这些构造函数/析构函数存在副作用,它们也可以被跳过。

3
如果可访问,符合标准的实现必须使用移动构造函数,详见12.8/32。 - MWid
我不是以英语为母语的人,所以“省略复制操作”是否意味着“移动操作”? - hl037_
1
“复制省略”在12.8/31中有定义。这包括复制构造函数和移动构造函数的省略。 - MWid
好的,我编辑了,现在我明白了 :) 谢谢 - hl037_

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接