请考虑以下示例:
#include <cstdio>
class object
{
public:
object()
{
printf("constructor\n");
}
object(const object &)
{
printf("copy constructor\n");
}
object(object &&)
{
printf("move constructor\n");
}
};
static object create_object()
{
object a;
object b;
volatile int i = 1;
// With #if 0, object's copy constructor is called; otherwise, its move constructor.
#if 0
if (i)
return b; // moves because of the copy elision rules
else
return a; // moves because of the copy elision rules
#else
// Seems equivalent to the above, but behaves differently.
return i ? b : a; // copies (with g++ 4.7)
#endif
}
int main()
{
auto data(create_object());
return 0;
}
Run Code Online (Sandbox Code Playgroud)
考虑一下C++ 11 Working Draft,n3337.pdf,12.8 [class.copy],第32点:
当满足或将满足复制操作的省略标准时,除了源对象是函数参数这一事实,并且要复制的对象由左值指定,重载决策选择复制的构造函数是首先执行,好像对象是由右值指定的.如果重载决策失败,或者所选构造函数的第一个参数的类型不是对象类型的rvalue引用(可能是cv-qualified),则再次执行重载决策,将对象视为左值.[注意:无论是否发生复制省略,都必须执行此两阶段重载决策.如果未执行elision,它将确定要调用的构造函数,并且即使调用被省略,也必须可以访问所选的构造函数. - 尾注]
因此,如果我们#if 1在示例中使用,则在返回对象时首先尝试移动构造函数,然后是复制构造函数.由于我们有一个移动构造函数,因此使用它来代替复制构造函数.
然而,在最后一个return语句中create_object(),我们发现没有使用移动构造函数.这是不是违反了语言规则?语言是否要求在最后一个return语句中使用移动构造函数?
How*_*ant 10
条件运算符的规范是如此复杂,这是可怕的.但我相信你的编译器的行为是正确的.见5.16 [expr.cond]/p4:
如果第二个和第三个操作数是相同值类别的glvalues并且具有相同的类型,则结果是该类型和值类别...
另请参见12.8 [class.copy],p31,b1,其中描述了何时允许复制省略:
在
return具有类返回类型的函数的语句中,当表达式是具有与函数返回类型相同的cv-非限定类型的非易失性自动对象(函数或catch子句参数除外)的名称时,复制/移动操作可以省略...
表达式不是自动对象的名称,而是条件表达式(并且该条件表达式是左值).因此,此处不允许复制省略,并且没有其他任何内容表明左值表达式可以假装为重载解析的右值.