[英]Copy constructor not called when initializing an object with return value of a function
Consider the following code: 请考虑以下代码:
#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;
}
The output of the above code with g++ file.cpp
is: 上面代码与
g++ file.cpp
的输出是:
Constructor
Constructor
Copy Constructor
Copy Constructor
The output of the above code with g++ -fno-elide-constructors file.cpp
is: 上面代码与
g++ -fno-elide-constructors file.cpp
是:
Constructor
Constructor
Copy Constructor
Copy Constructor
Copy Constructor
I know Return Value Optimization. 我知道返回值优化。 My question is which call to copy constructor is elided(temporary object during returning or returned object being copied to b)?
我的问题是哪个复制构造函数的调用被删除(返回期间的临时对象或被复制到b的返回对象)?
If the elided copy constructor is the one used for creating b, then how is b created at all (because there is no constructor call in this case also)? 如果省略的复制构造函数是用于创建b的构造函数,那么如何创建b(因为在这种情况下也没有构造函数调用)?
If I replace the line A b = a.fun(c);
如果我更换线
A b = a.fun(c);
with a.fun(c)
and compile using the first method or even the second method, then also the copy constructor is being called 2 times . 使用
a.fun(c)
并使用第一种方法甚至第二种方法进行编译,然后复制构造函数被调用2次。 So, if in the case explained in the previous paragraph, the temporary object's copy constructor is elided, then why isn't it elided in this case? 因此,如果在上一段中解释的情况下,临时对象的复制构造函数被省略了,那么为什么在这种情况下它没有被省略呢?
#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;
}
Yields: 产量:
Constructing: 0x7fffbb377220
Constructing: 0x7fffbb377210
Copy Constructor: 0x7fffbb377230 from 0x7fffbb377210
Copy Constructor: 0x7fffbb377200 from 0x7fffbb377230
a:0x7fffbb377220
b:0x7fffbb377200
c:0x7fffbb377210
So it constructs a
, constructs c
, copies c
to an intermediate (argument a
of the function), and then copies the intermediate directly into b
, skipping the typical copying of a to a return intermediate. 所以它构造
a
,构建c
,拷贝c
到中间(自变量a
函数),然后复制中间体直接进入b
,跳过的典型拷贝到中间回报。 This is even better demonstrated if you pass by value (change to A fun(const A& a)
: 如果你传递值,则更好地证明了这一点(改为
A fun(const A& a)
:
Constructing: 0x7fff8e9642b0
Constructing: 0x7fff8e9642a0
Copy Constructor: 0x7fff8e964290 from 0x7fff8e9642a0
a:0x7fff8e9642b0
b:0x7fff8e964290
c:0x7fff8e9642a0
a is constructed, c is constructed, c is copied directly to b, despite b not being passed to fun! a构造,c构造,c直接复制到b,尽管b没有传递给乐趣!
The copy that is elided is the copy of the temporary return value into b
. 省略的副本是临时返回值到
b
的副本。 Without elision the return value is initialized from a
and copied to b
. 如果没有省略,则返回值从
a
初始化并复制到b
。 Instead, the temporary that would otherwise hold the return value is constructed into b
and initialized with a
. 相反,将保存返回值的临时值构造为
b
并用a
初始化 。 [class.copy]/31: [class.copy] / 31:
when a temporary class object that has not been bound to a reference (12.2) would be copied/moved to a class object with the same cv-unqualified type, the copy/move operation can be omitted by constructing the temporary object directly into the target of the omitted copy/move
当一个未绑定到引用(12.2)的临时类对象被复制/移动到具有相同cv-nonqualified类型的类对象时,可以通过将临时对象直接构造到目标中来省略复制/移动操作省略的复制/移动
You can observe this if you add an additional output in fun
: 如果您在
fun
添加其他输出,则可以观察到此情况:
A fun(A a)
{
cout << "fun!" << endl;
return a;
}
Then with the elision you'll get 然后你将获得elision
[…]
[...]
fun!乐趣!
Copy Constructor复制构造函数
And without: 没有:
[…]
[...]
fun!乐趣!
Copy Constructor复制构造函数
Copy Constructor复制构造函数
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.