我有以下代码:
#include <iostream>
using namespace std;
struct A
{
A() {}
A(const A&) { cout << "copy const" << endl; }
A(A&) { cout << "copy non const" << endl; }
};
A f(A a)
{
return a;
}
int main() {
A a1 = f(A());
}
将调用A(A&)
复制构造函数。自从我传递了一个临时对象以来,为什么没有调用A(const A&)
?
当我注释掉A(const A&)
复制构造函数时,该程序无法编译。
答案 0 :(得分:8)
您看到的是copy elision和正在制作的实际副本的混合。由于f
取值为a
,因此需要将A()
复制到a
中。编译器认为确实不需要此副本,因此将其删除,而是直接构造a
,这样您就看不到任何调用。在f
的{{1}}正文中,它需要将return a;
复制到返回值中。由于a
是左值,因此a
比A(A&)
更好,因此您可以看到对非const复制构造函数的调用。然后需要根据A(const A&)
的返回值初始化a1
。复制省略再次发挥作用,没有看到复制而是直接将返回值放入f
的存储中。
因此,elide,非const副本,elide,仅使输出a1
删除copy non const
时会出错,因为即使删除了这些副本,C ++仍需要在C ++ 17之前具有副本构造函数。
如果使用gcc或clang进行编译并使用A(const A&)
,则实际上可以看到这些副本。您可以在此live example中看到这一点。请注意,我使用-fno-elide-constructors
关闭了C ++ 17的guaranteed copy elision