C++ 复制省略和右值

C++ 复制省略和右值,c++,c++11,C++,C++11,似乎复制省略的规则是参数必须是prvalue而不是xvalue,但为什么 似乎复制省略的规则是参数必须是prvalue而不是xvalue,但为什么 您的程序不包含可以执行复制/移动省略的情况。C++11标准在第12.8/31段中明确规定了这些情况: 当满足某些条件时,允许实现省略类的复制/移动构造 对象,即使为复制/移动操作选择了构造函数和/或为对象选择了析构函数 有副作用。[...] 在以下情况下,允许省略复制/移动操作,称为复制省略 可以组合使用以消除多个副本: -在具有类返回类型的函数中的

似乎复制省略的规则是参数必须是prvalue而不是xvalue,但为什么

似乎复制省略的规则是参数必须是prvalue而不是xvalue,但为什么

您的程序不包含可以执行复制/移动省略的情况。C++11标准在第12.8/31段中明确规定了这些情况:

当满足某些条件时,允许实现省略类的复制/移动构造 对象,即使为复制/移动操作选择了构造函数和/或为对象选择了析构函数 有副作用。[...] 在以下情况下,允许省略复制/移动操作,称为复制省略 可以组合使用以消除多个副本:

-在具有类返回类型的函数中的return语句中,当表达式是 非易失性自动对象,而不是具有相同cv的函数或catch子句参数 类型作为函数返回类型,可以通过构造 自动对象直接输入函数的返回值

这不是您的情况,因为运算符返回的表达式=是*This,它不是具有自动存储持续时间的对象的名称。此外,您也不会存储operator=的结果

-在抛出表达式中,当操作数是非易失性自动对象的名称而不是 函数或catch子句参数,其范围不超出最内层 封闭try块(如果有)从操作数到异常的复制/移动操作 通过将自动对象直接构造到异常对象中,可以省略对象15.1

这不适用,因为您没有抛出表达式

-复制/移动未绑定到参考12.2的临时类对象时 对于具有相同cv类型的类对象,可以通过 将临时对象直接构造到省略的复制/移动的目标中

这也不适用,因为您没有临时值xvalue不是临时值

-当异常处理程序的异常声明第15条声明了相同类型的对象时 除了作为例外对象15.1的cv限定外,复制/移动操作可以省略 通过将异常声明视为异常对象的别名,如果程序的含义 将保持不变,除了为声明的对象执行构造函数和析构函数 异常声明

代码中没有异常处理程序,因此这种情况也不适用

如果你想问的问题是为什么事情是这样的,那么我无法提供客观、详尽的答案,尽管其他人可能会这样做。但我会尝试提出一些似是而非的论点

正如上面引用的标准的段落所规定的,在返回语句的情况下,复制省略意味着允许函数将要返回的对象直接构造到指定的对象中

具体地说,这意味着编译器可能会为该函数生成代码,该代码直接作用于要向其分配返回值的对象,并且位于被调用函数的堆栈帧之外,而不是在函数的堆栈帧内分配了自动存储持续时间的本地对象上。这意味着您可以将本地对象视为指定对象的别名

然而,这里有两个非常不同的对象,它们都是物质构造的,都需要内存,并且位于两个不同的地址。无法应用类似于前面所述的技巧,因为这种别名需要在程序执行期间更改对象的地址,这是非法的

似乎复制省略的规则是参数必须是prvalue而不是xvalue,但为什么

您的程序不包含可以执行复制/移动省略的情况。C++11标准在第12.8/31段中明确规定了这些情况:

当满足某些条件时,允许实现省略类的复制/移动构造 对象,即使为复制/移动操作选择了构造函数和/或为对象选择了析构函数 有副作用。[...] 在以下情况下,允许省略复制/移动操作,称为复制省略 可以组合使用以消除多个副本:

-在具有类返回类型的函数中的return语句中,当表达式是 非易失性自动对象,而不是具有相同cv的函数或catch子句参数 类型作为函数返回类型, 复制/移动操作可以通过构造 自动对象直接输入函数的返回值

这不是您的情况,因为运算符返回的表达式=是*This,它不是具有自动存储持续时间的对象的名称。此外,您也不会存储operator=的结果

-在抛出表达式中,当操作数是非易失性自动对象的名称而不是 函数或catch子句参数,其范围不超出最内层 封闭try块(如果有)从操作数到异常的复制/移动操作 通过将自动对象直接构造到异常对象中,可以省略对象15.1

这不适用,因为您没有抛出表达式

-复制/移动未绑定到参考12.2的临时类对象时 对于具有相同cv类型的类对象,可以通过 将临时对象直接构造到省略的复制/移动的目标中

这也不适用,因为您没有临时值xvalue不是临时值

-当异常处理程序的异常声明第15条声明了相同类型的对象时 除了作为例外对象15.1的cv限定外,复制/移动操作可以省略 通过将异常声明视为异常对象的别名,如果程序的含义 将保持不变,除了为声明的对象执行构造函数和析构函数 异常声明

代码中没有异常处理程序,因此这种情况也不适用

如果你想问的问题是为什么事情是这样的,那么我无法提供客观、详尽的答案,尽管其他人可能会这样做。但我会尝试提出一些似是而非的论点

正如上面引用的标准的段落所规定的,在返回语句的情况下,复制省略意味着允许函数将要返回的对象直接构造到指定的对象中

具体地说,这意味着编译器可能会为该函数生成代码,该代码直接作用于要向其分配返回值的对象,并且位于被调用函数的堆栈帧之外,而不是在函数的堆栈帧内分配了自动存储持续时间的本地对象上。这意味着您可以将本地对象视为指定对象的别名

然而,这里有两个非常不同的对象,它们都是物质构造的,都需要内存,并且位于两个不同的地址。无法应用类似于前面所述的技巧,因为这种别名需要在程序执行期间更改对象的地址,这是非法的

#include <string> 
#include <iostream>

struct A 
{
   A (){}

    A(const A&)
    {
        std::cout << "copy" << "\n";
    }

    A& operator =(A)
    {
        return *this;
    }
}; 

int main()
{ 
    A  a;
    A a2;

    a=std::move(a2);

    std::cin.ignore();

    return 1;
}