2011-10-15 136 views
0

那么为什么拷贝构造函数没有在“const Integer运算符+(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() 
+1

你期望你的拷贝构造函数被调用的地方? –

+0

显示打印出的内容可以让我们更深入地了解您面临的实际情况。顺便说一句,你的拷贝构造函数不会复制任何东西。或者'I :: i'的复制构造函数是自动调用的?我不这么认为,但我不完全确定。 –

+1

@AndréPuel:他期待'operator +'返回时调用copy-ctor! – Nawaz

回答

4

的输出是因为视网膜静脉阻塞的。如果是,我需要做些什么来阻止它?

是的。但是由于编译器的Return Value Optimization而没有被调用。

如果您使用GCC,请使用-fno-elide-constructors选项来避免它。

GCC 4.6.1 manual说,

-fno-的Elid-构造

C++标准允许实现省略创建临时其仅用于初始化的相同类型的另一个目的。指定此选项将禁用该优化,并强制G ++在所有情况下调用复制构造函数。

+0

它工作。但是有没有其他方式可以通过编译器选项来实现。我打电话给内部运营商的本地对象打印+认为它会阻止RVO。 – nik

+0

@NikhilRathod:你是什么意思?什么工作?我所说的只是编译器选项,你还在谈论什么? – Nawaz

+0

编译器选项起作用。现在复制构造函数被称为 – nik

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,但事实是它会让您的代码更复杂,效率更低且难以维护。

+0

+1作为封面解释。 – Nawaz

相关问题