C++11标准规定,如果满足复制省略的条件(§12.8/31),则实现必须将作为返回值的本地lvalue变量和函数参数视为rvalue(移动)处理。如果重载分辨率没有成功地详细说明,那么它将被视为lvalue(复制)。
§12.8 [class.copy] p32
当满足复制操作的省略条件,或者只有源对象是函数参数这一事实不成立时,并且要复制的对象由lvalue指定时,首先应像该对象由rvalue指定一样执行选择复制构造函数的重载分辨率。如果重载解析失败,或者所选构造函数的第一个参数类型不是对象类型(可能带cv限定符)的rvalue引用,则再次执行重载分辨率,将对象视为lvalue。注意:无论是否会发生复制省略,都必须执行这个两阶段的重载分辨率。它确定要调用的构造函数,如果未执行省略,则所选构造函数必须是可访问的。 ——结束说明
这是否也包括成员子对象?我用以下代码片段进行了测试:
§12.8 [class.copy] p32
当满足复制操作的省略条件,或者只有源对象是函数参数这一事实不成立时,并且要复制的对象由lvalue指定时,首先应像该对象由rvalue指定一样执行选择复制构造函数的重载分辨率。如果重载解析失败,或者所选构造函数的第一个参数类型不是对象类型(可能带cv限定符)的rvalue引用,则再次执行重载分辨率,将对象视为lvalue。注意:无论是否会发生复制省略,都必须执行这个两阶段的重载分辨率。它确定要调用的构造函数,如果未执行省略,则所选构造函数必须是可访问的。 ——结束说明
这是否也包括成员子对象?我用以下代码片段进行了测试:
#include <iostream>
struct traced{
traced(){ std::cout << "default ctor\n"; }
traced(traced const&){ std::cout << "copy ctor\n"; }
traced(traced&&){ std::cout << "move ctor\n"; }
};
struct X{
traced t;
};
traced f(){
X x;
return x.t;
}
int main(){
traced t = f();
}
在Ideone上的实时示例。而且,无论是GCC 4.7 ToT还是Clang 3.1 ToT都不会显示“move ctor”,这让我相信标准不包括成员子对象。
我有什么遗漏了吗?我的测试代码出了问题吗?到底是什么导致输出结果如此?
f()
返回x,允许RVO。它使用了traced t = f().t;
,演示了移动。(我不知道这是否有帮助!) - Aaron McDaid