请考虑以下代码:
#include <iostream>
using namespace std;
class A
{
public:
int a;
A(): a(5)
{
cout << "Constructor\n";
}
A(const A &b)
{
a = b.a;
cout << "Copy Constructor\n";
}
A fun(A a)
{
return a;
}
};
int main()
{
A a, c;
A b = a.fun(c);
return 0;
}
以上代码g++ file.cpp
的输出为:
Constructor
Constructor
Copy Constructor
Copy Constructor
以上代码g++ -fno-elide-constructors file.cpp
的输出为:
Constructor
Constructor
Copy Constructor
Copy Constructor
Copy Constructor
我知道返回值优化。我的问题是哪个复制构造函数的调用被删除(返回期间的临时对象或被复制到b的返回对象)?
如果省略的复制构造函数是用于创建b的构造函数,那么如何创建b(因为在这种情况下也没有构造函数调用)?
如果我用A b = a.fun(c);
替换行a.fun(c)
并使用第一种方法甚至第二种方法进行编译,那么复制构造函数也会被调用2次。因此,如果在上一段中解释的情况下,临时对象的复制构造函数被省略了,那么为什么在这种情况下它没有被省略呢?
答案 0 :(得分:6)
#include <iostream>
using namespace std;
class A
{
public:
int a;
A(): a(5)
{
cout << "Constructing: " << (void *)this << std::endl;
}
A(const A &b)
{
a = b.a;
cout << "Copy Constructor: " << (void *)this << " from " << (void *)&b << std::endl;
}
A fun(A a)
{
return a;
}
};
int main()
{
A a, c;
A b = a.fun(c);
std::cout << "a:" << (void *)&a << std::endl <<
"b:" << (void *)&b << std::endl <<
"c:" << (void *)&c << std::endl;
return 0;
}
收率:
Constructing: 0x7fffbb377220
Constructing: 0x7fffbb377210
Copy Constructor: 0x7fffbb377230 from 0x7fffbb377210
Copy Constructor: 0x7fffbb377200 from 0x7fffbb377230
a:0x7fffbb377220
b:0x7fffbb377200
c:0x7fffbb377210
因此它构造a
,构造c
,将c
复制到函数的中间(参数a
),然后将中间体直接复制到{{1跳过典型的a复制到返回中间体。如果您按值传递(更改为b
:
A fun(const A& a)
a构造,c构造,c直接复制到b,尽管b没有传递给乐趣!
答案 1 :(得分:4)
被删除的副本是临时返回值到b
的副本。如果没有省略,则返回值从a
初始化并复制到b
。相反,将保留返回值的临时值构造为b
并使用a
进行初始化。 [class.copy] / 31:
当一个临时类对象尚未绑定到引用时 (12.2)将被复制/移动到具有相同的类对象 cv-unqualified类型,可以省略复制/移动操作 将临时对象直接构造到目标中 省略了复制/移动
如果您在fun
中添加其他输出,则可以观察到这一点:
A fun(A a)
{
cout << "fun!" << endl;
return a;
}
然后用elision你会得到
[...]
乐趣!
复制构造函数
没有:
[...]
乐趣!
复制构造函数
复制构造函数