那么为什么不在“ const Integer operator +(const Integer& rv)”函数中调用Copy构造函数。是因为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()
答案 0 :(得分:4)
是因为RVO吗?如果是,我需要做些什么才能防止它?
是。但是由于编译器的Return Value Optimization没有调用它。
如果您正在使用GCC,请使用-fno-elide-constructors
选项来避免它。
-fno-elide-constructors
C ++标准允许实现省略创建临时文件,该临时文件仅用于初始化相同类型的另一个对象。指定此选项会禁用该优化,并强制G ++在所有情况下都调用复制构造函数。
答案 1 :(得分:1)
(N)RVO是最容易实现的优化之一。在大多数按值返回的调用约定中,调用者保留返回对象的空间,然后将隐藏指针传递给函数。然后函数构造给定地址中的对象。也就是说,kk += ii + jj;
被翻译成:
Integer __tmp;
// __rtn this arg
Integer::operator+( &tmp, &ii, jj );
kk += __tmp;
该函数(在本例中为Integer::operator+
采用第一个隐藏参数__rtn
,该参数是指向sizeof(Integer)
字节的未初始化内存块的指针,其中将构造对象,第二个隐藏参数this
,然后是代码中函数的参数。
然后该函数的实现被翻译成:
Integer::operator+( Integer* __rtn, Integer const * this, const Integer &rv) {
cout << "operator+" << endl;
new (__rtn) Integer(i + rv.i);
__rtn->print();
}
因为调用约定传递指针,所以函数不需要为随后复制的本地整数保留额外的空间,因为它可以直接在代码中构建I
到接收的指针,并避免复制。
请注意,并非在所有情况下编译器都可以执行NRVO,特别是,如果函数中有两个本地对象,并且根据不能从代码中输入的条件返回任一个(比如参数的值)到功能)。虽然你可以这样做以避免RVO,但事实是它会使你的代码更复杂,效率更低,维护更难。