极客时间上一个c++教程,下面这段代码的输出是什么?
~~
#include <iostream>
using namespace std;
// Can copy and move
class A {
public:
A() { cout << "Create A\n"; }
~A() { cout << "Destroy A\n"; }
A(const A&) { cout << "Copy A\n"; }
A(A&&) {cout << "Move A\n";};
};
A getA_duang()
{
A a1;
A a2;
if (rand() > 42) {
return a1;
} else {
return a2;
}
}
int main()
{
auto a = getA_duang();
}~~
由于函数里添加了if等结构,因此不会进行拷贝消除,输出如下:
Create A
Create A
Move A
Destroy A
Destroy A
Destroy A
这里没毛病,有移动构造函数先走移动构造函数,没有的话走拷贝构造函数,作者下面这段我按照他的操作有点问题:
我将移动构造函数从代码里清除,调用确实是Copy A ,但如果改成A(A&&) =delete确报错:
c++14 c++17编译报错相同:
error: use of deleted function ‘A::A(A&&)’
下面评论里也没人提这个错误,是我理解错了吗?
程序简化一下吧:
注意
return
的地方在语义上是有一个 copy/move 的。stmt.return#2这个语义上的拷贝在 C++17 里也还存在,即使这个拷贝被 RVO 优化掉。所以,语义上,这里需要一个 copy/move constructor 。
C++17 里,是 prvalue 用于初始化一个对象的时候可能不需要调用拷贝,而是直接初始化。但是这里,是要先使用
a1
初始化结果“对象”(prvalue 在 C++17 里里已经不是一个对象),而因为a1
不是一个 prvalue,而是 lvalue ,所以需要一个 copy/move constructor。C++17 里,从返回的 prvalue 到被初始化变量的拷贝构造消失了。
(想这个程序里这样从函数返回一个对象再用于初始化另一个对象,实际是有两次初始化的,先由 return 之后的 表达式的结果 初始化 结果对象 ,然后由结果对象初始化被初始化的对象。在这里,就是先由
a1
初始化 result object ,再由 result object 初始化a
)你如果把 return 后面的表达式也搞成 prvalue ,那就彻底不需要 copy/move constructor 了。比如: