2009-11-27 179 views
1
#include <iostream> 
using namespace std; 

class X { 
     public: 
       X() { 
         cout<<"Cons"<<endl; 
       } 
       X(const X& x){ 
         cout<<"Copy"<<endl; 
       } 
       void operator=(const X& x){ 
         cout<<"Assignment called"; 
       } 
}; 

X& fun() { 
     X s; 
     return s; 
} 

int main(){ 
     X s = fun(); 
     return 0; 
} 

這段代碼也調用了拷貝構造函數。爲什麼這個工作?我記得我第一次運行這個程序時,它陷入了故障。但過了一段時間,它開始稱這個副本缺點。現在工作!奇怪的。g ++中奇怪的C++構造函數/拷貝構造函數問題

但是如果我更換,樂趣()如下:

X fun() { 
     X s; 
     return s; 
} 

然後複製利弊。不叫。我認爲副本缺點。在這種情況下會被調用。但正如@ flyfishr64指出的那樣,RVO即將在這裏發揮作用。但它仍不能解釋我返回參考的情況。我認爲它應該總是段錯誤。

任何解釋?

+0

你不能只說「但過了一段時間,它開始稱這個副本缺點,現在工作!!」 - 你一定改變了一些東西。 – Smashery 2009-11-27 04:33:08

+0

沒有。我做的唯一的事情是添加1 cout,然後刪除它。 – user855 2009-11-27 04:35:17

+0

很有可能。因爲當我嘗試以下時,複製構造函數未被調用。 X&fun(){X s;返回s; } int main(){X&x = fun();返回0; } 但是用這個理論,是不是不意味着返回局部變量的引用總是有效的?因爲如果我在主窗口中執行X s = fun(),那麼拷貝構造函數無論如何都會被調用? – user855 2009-11-27 04:45:40

回答

2

爲了擴大對@ flyfishr64的回答

複製構造函數調用這裏,因爲這:

X s = fun(); 

是初始化。您正在使用fun()來構造對象,而不是調用默認的構造函數。它相當於:

X s(fun()); 

您看到打印出的「缺點」是針對fun()中的實例。看到這篇文章:Assignment operator in C++瞭解更多。

2

在此代碼:

X fun() { 
     X s; 
     return s; 
} 

拷貝構造函數是沒有得到所謂,因爲返回值優化,讓編譯器旁路創建本地變量「s」和直接在返回的變量構建X 。

你可以閱讀更多關於RVO here

4

這將返回引用堆棧對象不一旦方法返回存在 - 堆棧unwinded,記憶依然存在,但如果把它修改成你不應該使用它

X& fun() { 
     X s; 
     return s; 
} 

X fun() { 
     X s; 
     return s; 
} 

您現在正在返回副本。如果編譯器非常聰明,它可能會做:

X fun() { 
    return X(); 
} 

在這種情況下,X在來電直接分配的堆棧,因此不需要該副本。

如果它segfault或不取決於如果您訪問無效的內存。

在您的示例中,您不訪問結構中的任何值。要查看段錯誤,請首先保留一個引用,您返回的fun()將一些變量添加到結構X中,並在從fun()返回後調用另一種在內部分配堆內存的方法(這應該覆蓋在fun中使用的原始內存)堆棧中的值(最好是0)。在此第二種方法返回後,嘗試使用從fun返回的原始參考打印出X的值...

0

當您返回對此類局部變量的引用時,您正在調用未定義的行爲。

它恰好在這種情況下工作,因爲class X的函數都沒有使用this指針,所以無關緊要,它不再有效。

+0

僅僅返回這樣的引用調用UB?你有參考嗎? – 2010-01-28 13:55:48