为什么这段代码中没有调用复制构造函数
那么为什么在“const Integer operator+(const Integer &rv)”函数中没有调用复制构造函数。是因为RVO吗? 如果是,我需要做什么来防止它?
#include <iostream>
using namespace std;
class Integer {
int i;
public:
Integer(int ii = 0) : i(ii) {
cout << "Integer()" << endl;
}
Integer(const Integer &I) {
cout << "Integer(const Integer &)" << endl;
}
~Integer() {
cout << "~Integer()" << endl;
}
const Integer operator+(const Integer &rv) const {
cout << "operator+" << endl;
Integer I(i + rv.i);
I.print();
return I;
}
Integer &operator+=(const Integer &rv) {
cout << "operator+=" << endl;
i + rv.i;
return *this;
}
void print() {
cout << "i: " << i << endl;
}
};
int main() {
cout << "built-in tpes:" << endl;
int i = 1, j = 2, k = 3;
k += i + j;
cout << "user-defined types:" << endl;
Integer ii(1), jj(2), kk(3);
kk += ii + jj;
}
如果我注释掉复制构造函数,我确实会收到错误。我期望当operator+返回时调用复制构造函数。以下是程序的输出
built-in tpes:
user-defined types:
Integer()
Integer()
Integer()
operator+
Integer()
i: 3 // EXPECTING Copy Constructor to be called after this
operator+=
~Integer()
~Integer()
~Integer()
~Integer()
So why is Copy constructor not being invoked in "const Integer operator+(const Integer &rv)" function. Is it because of RVO. If Yes what do I need to do to prevent it?
#include <iostream>
using namespace std;
class Integer {
int i;
public:
Integer(int ii = 0) : i(ii) {
cout << "Integer()" << endl;
}
Integer(const Integer &I) {
cout << "Integer(const Integer &)" << endl;
}
~Integer() {
cout << "~Integer()" << endl;
}
const Integer operator+(const Integer &rv) const {
cout << "operator+" << endl;
Integer I(i + rv.i);
I.print();
return I;
}
Integer &operator+=(const Integer &rv) {
cout << "operator+=" << endl;
i + rv.i;
return *this;
}
void print() {
cout << "i: " << i << endl;
}
};
int main() {
cout << "built-in tpes:" << endl;
int i = 1, j = 2, k = 3;
k += i + j;
cout << "user-defined types:" << endl;
Integer ii(1), jj(2), kk(3);
kk += ii + jj;
}
I do get an error If I'll comment out copy constructor. I'm expecting copy constructor to be called when operator+ returns. Following is the output of the program
built-in tpes:
user-defined types:
Integer()
Integer()
Integer()
operator+
Integer()
i: 3 // EXPECTING Copy Constructor to be called after this
operator+=
~Integer()
~Integer()
~Integer()
~Integer()
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(2)
是的。但由于编译器的返回值优化,它没有被调用。
如果您使用的是 GCC,请使用 -fno-elide-constructors 选项来避免它。
GCC 4.6.1手册说,
Yes. But it didn't get called because of Return Value Optimization by the compiler.
If you're using GCC, then use
-fno-elide-constructors
option to avoid it.GCC 4.6.1 manual says,
(N)RVO 是最容易实现的优化之一。在大多数按值返回的调用约定中,调用者为返回的对象保留空间,然后将隐藏指针传递给函数。然后该函数在给定的地址中构造对象。也就是说,
kk += ii + jj;
被翻译成如下形式:函数(在本例中
Integer::operator+
采用第一个隐藏参数__rtn< /code> 是一个指向
sizeof(Integer)
字节的未初始化内存块的指针,其中要构造对象,第二个隐藏参数this
,然后函数的参数然后函数的实现被翻译为:
因为调用约定传递指针,所以函数不需要为随后要复制的本地整数保留额外的空间,因为它可以只构建
I< /code> 在代码中直接插入接收到的指针,并避免复制。
请注意,并非在所有情况下编译器都可以执行 NRVO,特别是如果函数中有两个本地对象并且根据条件返回其中之一。这不能从代码中推断出来(比如参数的值虽然您可以这样做以避免 RVO,但事实是它会使您的代码更加复杂、效率更低并且更难以维护。
(N)RVO is one of the easiest to implement optimizations. In most calling conventions for return by value the caller reserves the space for the returned object and then passes a hidden pointer to the function. The function then constructs the object in the address that is given. That is,
kk += ii + jj;
is translated into something like:The function (in this case
Integer::operator+
takes a first hidden argument__rtn
that is a pointer to an uninitialized block of memory ofsizeof(Integer)
bytes, where the object is to be constructed, a second hidden argumentthis
, and then the argument to the function in the code.Then the implementation of the function is translated into:
Because the calling convention passes the pointer, there function does not need to reserve extra space for a local integer that would then be copied, as it can just build the
I
in your code straight into the received pointer, and avoid the copy.Note that not in all circumstances the compiler can perform NRVO, in particular, if you have two local objects in the function and you return either one depending on a condition that is not inferable from the code (say the value of an argument to the function). While you could do that to avoid RVO, the fact is that it will make your code more complex, less efficient and harder to maintain.