2011-11-14 23 views
9
class x 
{ 
    int a; 
public: 
    x() 
    { 
     cout<<"\n\ndefault constructor"; 
    } 
    x(x& obj) 
    { 
     cout<<"\n\ncopy constructor"; 
    } 
    x fun() 
    { 
     x ob; 
     return ob; 
    } 
}; 
int main() 
{ 
    x ob1; 
    x ob2=ob1.fun(); 
    return 0; 
} 

最初,此代碼給了一個錯誤「不匹配函數調用‘X :: X(X)’」, 當我改變了複製構造到常量在C複製構造++

x(const x& obj) 
{ 
    cout<<"\n\ncopy constructor"; 
} 

輸出變爲

默認構造函數

默認構造函數
仍然拷貝構造函數不執行....爲什麼?

+0

http://stackoverflow.com/questions/1932700/copy-constructor-not-called-but-compiler-complains-that-theres-no – Mat

回答

13

這就是編譯器所做的copy-elision,這是語言規範所允許的。

看到這個維基條目:

至於爲什麼非const版本是給編譯錯誤,因爲obj1.fun()回報不能綁定到非const引用臨時對象,但它可以綁定到const引用,所以const版本編譯得很好。一旦你使用const引用,它只用於語義檢查,但是編譯器會優化代碼,從而減少對copy-constructor的調用。

但是,如果您使用GCC的-fno-elide-constructors選項進行編譯,則不會執行copy-elision,並且將調用複製構造函數。的GCC doc說,

-fno-的Elid-構造

C++標準允許實現省略創建臨時其僅用於初始化的相同類型的另一個目的。 指定此選項將禁用該優化,並強制G ++在所有情況下調用複製構造函數。

+1

很好的回答!謝謝。 – russoue

1

臨時值是右值,不綁定到非常量引用。因此ob1.fun()無法綁定到x::x(x&)構造函數。

但是,右值綁定到常數參考。

至於爲什麼沒有輸出:拷貝構造函數是標準的特殊情況,編譯器被允許複製的Elid構造函數調用,即使拷貝構造函數有副作用。但是,建設必須仍然有效!另一個這樣的例子是,如果你聲明瞭複製構造函數explicit - 它仍然會被忽略,但是你的代碼是錯誤的。

在海灣合作委員會,你可以說-fno-elide-constructors帶回你的構造函數。

3

編譯器決定,因爲它是允許做優化出來的拷貝構造,即使接受const引用的論據。

1

第一個錯誤是因爲它試圖對臨時對象使用複製構造函數。

ob1.fun(); // This returns an x by value 

因此,當你使用它聽到

x ob2=ob1.fun();  // You are passing it by value which requires a local temporary 
// This is equivalent to this: 
x ob2(obj1.fun()); // So it is trying to do a copy construction. 

臨時變量只能綁定爲const引用。因此它無法編譯。

修復該問題後(臨時),現在可以使用複製構造函數。但是如果可以的話,編譯器可以優化它。它不能優化它,因爲它甚至不允許在第一個版本中使用它。

1

由於複製elision優化,您的副本構造函數調用被跳過。您不能依賴複製構造函數(如print語句)中的任何可觀察行爲。如果您確實想查看它的輸出,請嘗試禁用優化。