复制检查和右值 [英] copy elision and rvalue

查看:128
本文介绍了复制检查和右值的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

#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;
}

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

It seems that the rule for copy elision is that the argument must be an prvalue and not a xvalue but why ?

推荐答案


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

It seems that the rule for copy ellision is that the argument must be an prvalue and not a xvalue but why?

您的程序不包含可执行复制/ 。 C ++ 11标准详细说明了12.8 / 31中的这些情况:

Your program does not contain a situation where copy/move elision can be performed. The C++11 Standard specifies exactly these situations in Paragraph 12.8/31:


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

When certain criteria are met, an implementation is allowed to omit the copy/move construction of a class object, even if the constructor selected for the copy/move operation and/or the destructor for the object have side effects. [...] This elision of copy/move operations, called copy elision, is permitted in the following circumstances (which may be combined to eliminate multiple copies):

- 在函数中的返回语句中,返回类型为,当表达式是
的名称时非易失性自动对象(函数或catch子句参数除外)具有与函数返回类型相同的cv非限定
类型,可以通过将自动对象直接构造为
来省略复制/移动操作函数的返回值

— in a return statement in a function with a class return type, when the expression is the name of a non-volatile automatic object (other than a function or catch-clause parameter) with the same cv-unqualified type as the function return type, the copy/move operation can be omitted by constructing the automatic object directly into the function’s return value

这不是你的情况,因为表达式 return ed由 operator = * this ,这不是具有自动存储持续时间的对象的名称。此外,您还不存储 operator = 的结果。

This is not your situation, because the expression returned by your operator = is *this, which is not the name of an object with automatic storage duration. Moreover, you are not storing the result of operator = anyway.


一个throw-expression,当操作数是一个非易失性自动对象(除了
函数或catch子句参数)的名称,其范围不会超出最内层
的结尾-block(如果有的话),从操作数到异常
对象(15.1)的复制/移动操作可以通过将自动对象直接构造为异常对象来省略

— in a throw-expression, when the operand is the name of a non-volatile automatic object (other than a function or catch-clause parameter) whose scope does not extend beyond the end of the innermost enclosing try-block (if there is one), the copy/move operation from the operand to the exception object (15.1) can be omitted by constructing the automatic object directly into the exception object

这不适用,因为您没有 throw 表达式。

This does not apply, because you have no throw expression.


- 当未绑定到引用(12.2)的临时类对象将被复制/移动
到类对象相同的cv非限定类型,
可以省略复制/移动操作直接进入省略的复制/移动目标的临时对象

— when a temporary class object that has not been bound to a reference (12.2) would be copied/moved to a class object with the same cv-unqualified type, the copy/move operation can be omitted by constructing the temporary object directly into the target of the omitted copy/move

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

This does not apply either, because you have no temporaries (an xvalue is not a temporary).


- 当异常处理程序的异常声明(第15条)声明一个类型为
(cv-qualification除外)作为异常对象(15.1)的对象时,复制/可以省略
通过将异常声明作为异常对象的别名处理,如果程序
的含义将保持不变,除了执行由
声明的对象的构造函数和析构函数异常声明。

— when the exception-declaration of an exception handler (Clause 15) declares an object of the same type (except for cv-qualification) as the exception object (15.1), the copy/move operation can be omitted by treating the exception-declaration as an alias for the exception object if the meaning of the program will be unchanged except for the execution of constructors and destructors for the object declared by the exception-declaration.

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

There is no exception handler in your code, so this situation does not apply either.

如果你想要的问题是为什么是事情的方式?,没有客观,详尽的答案我能够提供(虽然其他人可能)。

If your intended question is "Why are things the way they are?", there is no objective, exhaustive answer that I am able to provide (though others might). But I will try to bring on some plausible arguments.

根据上面引用的标准段落的规定,在的情况下复制elision, return 语句意味着该函数允许构造直接返回到分配对象中的对象。

As specified by the paragraph of the Standard quoted above, copy elision in the case of a return statement means that the function is allowed to construct the object being returned directly into the assigned object.

具体来说,这意味着编译器可能会为该函数生成代码,该代码直接在要为其分配返回值的对象上,并且生命外部,而不是在函数的堆栈帧中自动存储持续时间分配给 的本地对象。这意味着你可以看到本地对象作为指定的别名的别名。

Concretely, this means that the compiler will probably produce code for that function that works directly on the object to which the return value is to be assigned, and that lives outside of the invoked function's stack frame, rather than on a local object with automatic storage duration allocated inside the function's stack frame. This means you can see the local object as an alias for the assigned one.

但是,这里你有两个非常不同的对象,构造,它们都需要存储器并且存在于两个不同的地址。没有办法应用类似于之前概述的技巧,因为这种别名将需要在程序执行期间更改对象的地址 - 这是非法的。

However, here you have two very distinct objects, both materially constructed, both of which require memory and live at two different addresses. There is no way to apply a trick similar to the one outlined previously, because that kind of aliasing would require changing the address of an object during a program's execution - and that's illegal.

这篇关于复制检查和右值的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆