为什么这个程序调用复制构造函数而不是移动构造函数?
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
return q.x > x ? q : e;
用于禁用 nrvo。当我把它包起来时std::move
,确实是感动了。但在《A Tour of C++》中,作者说 move c'tor 必须在可用时调用。
我做错了什么?
您没有以允许发生复制/移动省略的方式编写函数。副本替换为移动的要求如下:
[类.复制.省略]/3 https://timsong-cpp.github.io/cppwp/n4659/class.copy.elision#3:
在下面的复制初始化上下文中,移动操作可能
用来代替复制操作:
- 如果 return 语句中的表达式是 a (可能带括号)id-表达式使用自动命名对象
正文中声明的存储期限或参数声明子句最里面的封闭函数或lambda 表达式
首先是选择副本构造函数的重载决策
执行起来就像对象是由右值指定的一样。如果第一个
重载决策失败或未执行,或者如果
所选构造函数的第一个参数不是右值引用
对于对象的类型(可能是 cv 限定的),重载决策是
再次执行,将该对象视为左值。
以上来自C++17,但C++11的措辞几乎相同。条件运算符is not一个在函数范围内命名对象的 id 表达式。
id 表达式会是这样的q
or e
在你的具体情况下。你需要name该范围内的对象。条件表达式不符合命名对象的条件,因此它必须执行副本。
如果您想在困难的文本墙上锻炼您的英语理解能力,那么这就是 C++11 的编写方式。需要一些努力才能看到 IMO,但它与上面的澄清版本相同:
当满足某些标准时,允许实施省略
类对象的复制/移动构造,即使复制/移动
对象的构造函数和/或析构函数有副作用。 [...]
这种复制/移动操作的省略称为复制省略,是
在以下情况下允许(可以组合起来)
消除多个副本):
- 在具有类返回类型的函数的 return 语句中,当表达式是非易失性自动对象的名称(其他
比函数或 catch 子句参数)具有相同的
cv-非限定类型作为函数返回类型,复制/移动
直接构造自动对象可以省略操作
进入函数的返回值
当满足或将满足复制操作省略的标准时
满足保存源对象是函数参数的事实,
并且要复制的对象由左值、重载指定
首先执行选择副本构造函数的决议
就好像该对象是由右值指定的一样。如果过载解析
失败,或者如果所选的第一个参数的类型
构造函数不是对象类型的右值引用(可能
cv 限定),再次执行重载决策,考虑到
对象作为左值。
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)