按值复制而不是移动返回 [英] Return by value copies instead of moving

查看:52
本文介绍了按值复制而不是移动返回的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

为什么该程序调用复制构造函数而不是move构造函数?

Why does this program call the copy constructor instead of the move constructor?

class Qwe {
public:
    int x=0;
    Qwe(int x) : x(x){}
    Qwe(const Qwe& q) {
        cout<<"copy ctor\n";
    }
    Qwe(Qwe&& q) {
        cout<<"move ctor\n";
    }    
};

Qwe foo(int x) {
    Qwe q=42;
    Qwe e=32;
    cout<<"return!!!\n";
    return q.x > x ? q : e;
}

int main(void)
{
    Qwe r = foo(50);
}

结果是:

return!!!
copy ctor

返回q.x> X ? q:e; 用于禁用nrvo。当我将其包装在 std :: move 中时,它确实被移动了。但是在 A C ++之旅中,作者说必须举动c'tor。

return q.x > x ? q : e; is used to disable nrvo. When I wrap it in std::move, it is indeed moved. But in "A Tour of C++" the author said that the move c'tor must be called when it available.

我做错了什么?

推荐答案

您未以允许复制/移动省略发生的方式编写函数。要通过移动替换副本的要求如下:

You did not write your function in a way that allows copy/move elision to occur. The requirements for a copy to be replaced by a move are as follows:

/ 3


在以下 copy-initialization 上下文中,可以使用
而不是复制操作来进行移动操作:

In the following copy-initialization contexts, a move operation might be used instead of a copy operation:


  • 如果return语句中的表达式是一个(可能带有括号的) id-expression ,该对象使用在主体中声明的自动
    存储持续时间或$ b $来命名对象b最内层封闭函数或 lambda-expression
  • parameter-declaration-clause
  • If the expression in a return statement is a (possibly parenthesized) id-expression that names an object with automatic storage duration declared in the body or parameter-declaration-clause of the innermost enclosing function or lambda-expression

为副本选择构造函数的重载决议首先执行
,就像该对象由右值指定一样。如果第一个
重载解析失败或未执行,或者所选构造函数的
第一个参数的类型不是右值,则将
引用到该对象的类型(可能是cv限定的) ,则将对象视为左值,再次执行
重载解析。

overload resolution to select the constructor for the copy is first performed as if the object were designated by an rvalue. If the first overload resolution fails or was not performed, or if the type of the first parameter of the selected constructor is not an rvalue reference to the object's type (possibly cv-qualified), overload resolution is performed again, considering the object as an lvalue.

上面是C ++ 17的代码,但是C ++ 11的措辞几乎相同。条件运算符不是在函数范围内命名对象的id表达式。

The above is from C++17, but the C++11 wording is pretty much the same. The conditional operator is not an id-expression that names an object in the scope of the function.

id表达式类似于 q e 。您需要命名该范围内的对象。条件表达式不符合命名对象的条件,因此必须执行一个副本。

An id-expression would be something like q or e in your particular case. You need to name an object in that scope. A conditional expression doesn't qualify as naming an object, so it must preform a copy.

如果要锻炼身体您的英语理解能力在困难的文字墙上,然后这就是用C ++ 11编写的方式。花费一些精力查看IMO,但与上面澄清的版本相同:

If you want to exercise your English comprehension abilities on a difficult wall of text, then this is how it's written in C++11. Takes some effort to see IMO, but it's the same as the clarified version above:


当满足某些条件时,允许实现忽略
复制/移动类对象的构造,即使该对象的
构造函数和/或析构函数的复制/移动也有副作用。 [...]
在以下情况下,允许
使用复制/移动操作的这种删减方式,称为复制删减(可以合并为
以消除多个副本):

When certain criteria are met, an implementation is allowed to omit the copy/move construction of a class object, even if the copy/move constructor and/or 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-clause参数),而
    cv-unqual类型与函式传回类型相同,则可以直接将自动物件
    建构至函式中,从而省略复制/移动
    作业函数的返回值

当满足复制操作省略标准或将满足
时,以下事实除外源对象是一个函数参数,
,要复制的对象由一个左值指定,重载
的分辨率以选择要复制的构造函数,首先执行
,就像指定了该对象一样通过一个右值。如果重载解析
失败,或者所选
构造函数的第一个参数的类型不是对该对象类型的右值引用(可能是
cv限定),则再次执行重载解析,将
对象视为左值。

When the criteria for elision of a copy operation are met or would be met save for the fact that the source object is a function parameter, and the object to be copied is designated by an lvalue, overload resolution to select the constructor for the copy is first performed as if the object were designated by an rvalue. If overload resolution fails, or if the type of the first parameter of the selected constructor is not an rvalue reference to the object's type (possibly cv-qualified), overload resolution is performed again, considering the object as an lvalue.

这篇关于按值复制而不是移动返回的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

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