【发布时间】:2012-02-07 20:06:03
【问题描述】:
C++11 标准规定,如果满足复制省略的条件 (§12.8/31),则实现应将 returned 局部左值变量和函数参数视为右值优先(移动),如果重载解析没有成功,则应将其视为左值(副本)。
§12.8 [class.copy] p32
当满足或将满足删除复制操作的条件时,除了源对象是函数参数这一事实之外,并且要复制的对象由左值指定,重载决议选择复制的构造函数首先执行,就好像对象是由右值指定的一样。如果重载决议失败,或者如果所选构造函数的第一个参数的类型不是对对象类型的右值引用(可能是 cv 限定的),则再次执行重载决议,将对象视为左值。 [ 注意: 无论是否会发生复制省略,都必须执行此两阶段重载解决方案。它确定如果不执行省略则要调用的构造函数,并且即使调用被省略,所选构造函数也必须是可访问的。 ——尾注 ]
这是否也包括成员子对象?我用下面的 sn-p 进行了测试:
#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();
}
Live example on Ideone. 而且 GCC 4.7 ToT 和 Clang 3.1 ToT 都不会显示“move ctor”,这让我相信标准不包括成员子对象。
我是否忽略了什么?我的测试代码坏了吗?究竟是什么导致输出保持原样?
【问题讨论】:
-
我不认为你的测试证明他们不能。它可能只是表明编译器很难确认
criteria for elision已经满足,因为突出显示的部分只有在编译器可以确认标准有效时才相关。 -
我有点困惑。我想我混合了返回值优化和复制省略。我稍微调整了代码并得到了移动,请参阅this demo。我直接从
f()返回 x,允许 RVO。它使用traced t = f().t;来演示这一举动。 (我不知道这是否有帮助!) -
@Aaron。 RVO 只是复制省略的一种应用。 :) 一个适当的子集,可以这么说。此外,返回后访问的好主意。可悲的是,这不适用于我的实际代码。 ://
标签: c++ c++11 local-variables move-semantics