复制临时对象的构造函数调用

时间:2020-01-23 20:33:33

标签: c++

我有以下代码:

#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&)复制构造函数时,该程序无法编译。

1 个答案:

答案 0 :(得分:8)

您看到的是copy elision和正在制作的实际副本的混合。由于f取值为a,因此需要将A()复制到a中。编译器认为确实不需要此副本,因此将其删除,而是直接构造a,这样您就看不到任何调用。在f的{​​{1}}正文中,它需要将return a;复制到返回值中。由于a是左值,因此aA(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