似乎复制省略的规则是参数必须是prvalue而不是xvalue,但为什么呢?
您的程序不包含可以执行复制/移动省略的情况。C++11 标准在第 12.8/31 段中明确规定了这些情况:
当满足某些条件时,允许实现省略类对象的复制/移动构造,即使为复制/移动操作选择的构造函数和/或对象的析构函数具有副作用。[...]
这种复制/移动操作的省略,称为复制省略,在以下情况下是允许的(可以结合起来消除多个副本):
— 在具有类返回类型的函数的 return 语句中,当表达式是具有与函数返回类型相同的 cv 非限定类型的非易失性自动对象(函数或 catch 子句参数除外)的名称时,可以通过将自动对象直接构造到函数的返回值中来省略复制/移动操作
这不是您的情况,因为您的表达式return
是operator =
,*this
它不是具有自动存储持续时间的对象的名称。operator =
此外,无论如何,您都不会存储结果。
— 在 throw 表达式中,当操作数是非易失性自动对象(函数或 catch 子句参数除外)的名称时,其范围不超出最里面的封闭 try 块的末尾(如果有一)、从操作数到异常对象(15.1)的复制/移动操作可以通过将自动对象直接构造到异常对象中来省略
这不适用,因为你没有throw
表情。
— 当尚未绑定到引用 (12.2)的临时类对象将被复制/移动到具有相同 cv-unqualified 类型的类对象时,可以通过将临时对象直接构造到省略复制/移动的目标
这也不适用,因为您没有临时变量(xvalue不是临时变量)。
— 当异常处理程序的异常声明(第 15 条)声明与异常对象(15.1)具有相同类型的对象(cv 限定除外)时,可以通过处理异常声明来省略复制/移动操作作为异常对象的别名,如果程序的含义将保持不变,除了为异常声明声明的对象执行构造函数和析构函数。
您的代码中没有异常处理程序,因此这种情况也不适用。
如果您的预期问题是“为什么事情会这样? ”,那么我无法提供客观、详尽的答案(尽管其他人可能)。但我会尝试提出一些似是而非的论点。
正如上面引用的标准段落所指定的,在return
语句的情况下复制省略意味着允许函数将要返回的对象直接构造到分配的对象中。
具体来说,这意味着编译器可能会为该函数生成代码,该代码直接在要分配返回值的对象上工作,并且位于被调用函数的堆栈框架之外,而不是在具有自动存储功能的本地对象上在函数的堆栈框架内分配的持续时间。这意味着您可以将本地对象视为已分配对象的别名。
但是,这里有两个非常不同的对象,它们都是物质构造的,它们都需要内存并且位于两个不同的地址。没有办法应用类似于前面概述的技巧,因为这种别名需要在程序执行期间更改对象的地址——这是非法的。