C++ 按值返回副本,而不是移动
为什么这个程序调用复制构造函数而不是移动构造函数C++ 按值返回副本,而不是移动,c++,c++11,C++,C++11,为什么这个程序调用复制构造函数而不是移动构造函数 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) { Qw
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);
}
返回q.x>x?q:e代码>用于禁用nrvo。当我将它包装在std::move
中时,它确实被移动了。但是在“C++之旅”中,作者说,当move C'tor可用时,必须调用它
我做错了什么?您编写函数的方式不允许出现复制/移动省略。用移动替换副本的要求如下:
:
在以下复制初始化上下文中,可能会执行移动操作
用于替代复制操作:
- 如果return语句中的表达式是使用automatic
正文中声明的存储持续时间或
最里面的封闭函数或lambda表达式的参数声明子句
选择副本构造函数的重载解析是第一个
像对象由右值指定一样执行。如果第一个
重载解析失败或未执行,或者
所选构造函数的第一个参数不是右值引用
对于对象的类型(可能是cv限定),重载解析为
再次执行,将对象视为左值
上面的内容来自C++17,但C++11的措辞基本相同。条件运算符不是为函数范围内的对象命名的id表达式
在您的特定情况下,id表达式类似于q
或e
。您需要在该范围内命名一个对象。条件表达式不符合命名对象的条件,因此它必须预先生成副本
如果你想在一堵难懂的文本墙上锻炼你的英语理解能力,那么这就是C++11的编写方法。需要一些努力才能看到IMO,但与上面澄清的版本相同:
当满足某些条件时,允许实现省略
类对象的复制/移动构造,即使复制/移动
对象的构造函数和/或析构函数有副作用。[...]
这种复制/移动操作的省略称为复制省略
在以下情况下允许(可合并为
消除多个副本):
- 在具有类返回类型的函数中的return语句中,当表达式是非易失性自动对象(其他)的名称时
比函数或catch子句参数)具有相同的
cv不合格类型作为函数返回类型,复制/移动
通过直接构造自动对象,可以省略操作
输入函数的返回值
当满足或将满足省略复制操作的条件时
met save,因为源对象是函数参数,
要复制的对象由左值重载指定
首先执行为副本选择构造函数的解析
好像对象是由右值指定的。If重载解析
失败,或者如果选择的第一个参数的类型
构造函数不是对对象类型的右值引用(可能是
cv合格),考虑到
对象作为左值
讲故事的人没有回答这个问题:为什么不叫搬家人?(而不是:为什么没有拷贝省略?)
我的建议是:只有在以下情况下才会调用move c'tor:
- 不执行复制省略(RVO)。使用三元运算符确实是防止复制省略的一种方法。让我指出,
返回(0,q)如果您只想在抑制复制省略的同时返回q
,则code>是一种更简单的方法。它使用(in-)著名的逗号运算符。可能返回((q))代码>也可能有用,但我不是一个足够的语言律师,不能肯定地说
return
的参数是一个右值。这可能是一个临时值(更准确地说,是一个PR值),但它们也有资格进行复制省略。因此,return
的参数必须是一个xvalue,例如std::move(q)
,如果您想确保调用move c'tor
另见:
您的示例还有一些技术细节:
q
和e
是Qwe
类型的对象
q.x>x?q:e
是类型为Qwe
的左值表达式。这是因为表达式q
和e
是Qwe
类型的左值。三元运算符只选择其中一个
std::move(q.x>x?q:e)
是类型为Qwe
的xvalue表达式。std::move
只需将左值转换为x值。顺便说一句,q.x>x?std::move(q):std::move(e)
也可以
return q.x>x中调用复制任务?q:e
因为它可以用类型为Qwe
的左值调用(constness是可选的),而另一方面,move c'tor不能用左值调用,因此从候选集中删除更新:通过更深入的方式来评论评论…这是C++的一个非常令人困惑的方面。p> 从概念上讲,在C++98中,按值返回对象意味着返回对象的副本,因此将调用copy C'tor。然而,该标准的作者认为,编译器应该可以自由地执行优化,以便在适当的情况下可以省去这一潜在的昂贵副本(例如容器)
这种复制省略意味着,被调用方不是在一个地方创建对象,然后将其复制到调用方控制的内存地址,而是直接在调用方控制的内存中创建对象。因此,只有