2011-10-15 75 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

相關問題