2013-04-12 22 views
0

我知道使用引用返回臨時變量不起作用,因爲臨時對象在函數終止後會丟失,但由於返回的臨時對象被分配給另一個對象,因此下面的代碼片段可以工作。使用引用行爲不同的返回tmp

我假設臨時對象在函數調用行後被銷燬。如果是這樣,爲什麼這種方法不適用於這種方法鏈?

Counter& Counter::doubler() 
{ 
    Counter tmp; 
    tmp.i = this->i * 2; 
    return tmp; 
} 

int main() 
{ 
    Counter d(2); 
    Counter d1, d2; 
    d1 = d.doubler();       // normal function call 
    std::cout << "d1=" << d1.get() << std::endl; // Output : d1=4 
    d2 = d.doubler().doubler();     // Method chaining 
    std::cout << "d2=" << d2.get() << std::endl; // Output : d2=0 
    return 0; 
} 

回答

0
Counter& doubler() 
{ 
Counter tmp; 
tmp.i=this->i*2; 
return tmp; 
} 

這是不確定的行爲。從函數返回後 - 您的引用將是懸空的,因爲Counter析構函數將被調用爲本地對象tmp

3

如果一個函數返回一個對本地對象的引用,只要函數返回(就像本地對象一樣),對象就會被銷燬。它不會而不是堅持到函數調用行的末尾。

訪問一個對象被銷燬後會產生不可預知的結果。有時它可能起作用,因爲某些「工作」的定義,有時它可能不起作用。只是不要這樣做。

+0

怎麼樣R值參考在C + + 11? – shivakumar

+0

@ shivakumar:如果你想談論他們,請提出一個新問題。這對於這個簡單的問題來說有點超出範圍。 ;) –

+0

正如你所說,對於某些工作的定義,它會起作用。我說它總是適用於問題中提出的簡單對象和簡單代碼。請參閱下面的答案。 – Amit

0

您正在返回對本地(臨時)對象的引用。退出該功能後它是未定義的行爲。

因爲tmp在返回函數後會被銷燬。所以,返回的引用無效。

0

真正的問題不是「爲什麼這種方法鏈不工作?」,而是「爲什麼第一個('正常')函數調用工作?」

答案是沒有辦法告訴,因爲它可能會打破你的程序。

要清楚地說明:通過引用返回臨時對象是未定義的行爲。當然,這意味着它今天可能巧合工作,明天停止工作。所有投注都關閉。

0

當一個函數返回並且發生堆棧回滾時,這是邏輯回滾,堆棧指針被設置爲不同的值。如果一個函數返回一個局部變量引用,那麼指向本地的內存位置可能仍然是進程並且具有相同的位集。但是,這並不能保證,並且在幾次更多的調用將無效並可能導致未定義的行爲。

0

其他都沒事,在這「只是不擺弄本地對象的引用」

但至於爲什麼它在一種情況下,而不是在其他

  1. 當您打電話它是單獨的,當函數返回時,對象仍然躺在堆棧上。授予一個「破壞」的對象 - 但是無論對象曾經採取的任何空間仍然在堆棧中。如果你有一個簡單的對象,就像一個int成員一樣,那麼除非你在堆棧上分配了其他東西,或者析構函數決定做一個更徹底的工作並消除一個整數成員大多數破壞者不會這樣做)。授予yada yada,但直到下一行沒有太多的事情會發生,將它從棧中移出。你的引用指向一個有效的內存位置,你的(被破壞的)對象將會在那裏。這就是爲什麼它適合你。

  2. 當您將它稱爲鏈接時,請參閱第一個調用返回給您對該堆棧中該tmp的引用。如上面#1所述,目前沒有問題。你的(被破壞的)tmp仍然非常重要。但注意你稱之爲第二倍的時刻。第二個doubler函數調用會在什麼地方出現?從你的第一個電話tmp正確的地方!第二次調用用值爲0的tmp(默認構造的一個)覆蓋對象(值爲4的tmp)。第二個調用實際上是在一個有0值的計數器上產生的,因此你得到0.非常棘手 - 這就是爲什麼忘記了返回引用局部變量的問題。

現在純粹主義者可能會尖叫 - 不確定的,不,不只是沒有做到這一點 - 我與他們 - 我有我自己兩次說(現在是三次)沒有做到這一點。但人們可能會嘗試。我敢打賭,像下面這樣的「簡單」對象,AND代碼與問題完全相同(因爲沒有什麼會干擾堆棧),每個人都會得到一致的4,0 - 沒有隨機性,沒有未定義的...。

class Counter 
{ 
public: 
    Counter() 
    { 
     i = 0; 
    } 
    Counter(int k) 
    { 
     i = k; 
    } 
    int get() 
    { 
     return i; 
    } 
    int i; 
    Counter& doubler(); 
}; 
相關問題