2012-02-19 87 views
3

下面的代碼給出了g ++版本4.6.2的一個例外,但是按照g ++版本4.2.1的預期運行。在執行過程中打印的消息表明,在這兩種情況下,一個析構函數正在被調用的地址是從未構建的。我想知道(a)哪些編譯器是正確的,(b)爲什麼某些東西在不被創建的情況下被銷燬。非常感謝。析構函數被調用的東西不是構造的

//------------------------------------------------------ 
#include <iostream> 
using namespace std; 

class Poly{ 
private: 
    float *coeff; 
public: 
    Poly(){ 
    coeff = NULL; 
    cout << "Created "<< this << endl; 
    } 
    Poly(Poly const & p){   // copy constructor 
    coeff = NULL; 
    cout << "Executed copy constructor.\n"; 
    } 
    Poly operator=(Poly const & rhs){ 
    cout << "Executed assignment. " << this << " = " << &rhs << endl; 
    } 
    Poly fun(){ 
    Poly c; 
    return c; 
    } 
    ~Poly(){ 
    cout << "Destructor: " << this << endl; 
    delete[] coeff; 
    } 
}; 


main(){ 
    Poly a; 
    a = a.fun(); 
} 
//------------------------------------------------------ 

對於G ++ 4.6.2它給和異常:

% ./a.out 
Created 0xbfdcc184 
Created 0xbfdcc18c 
Executed assignment. 0xbfdcc184 = 0xbfdcc18c 
Destructor: 0xbfdcc188 
*** glibc detected *** free(): invalid pointer: 0xbfdcc1a8 *** 
Aborted 

對於G ++ 4.2.1它下面

% ./a.out 
Created 0x7fff5fbff930 
Created 0x7fff5fbff920 
Executed assignment. 0x7fff5fbff930 = 0x7fff5fbff920 
Destructor: 0x7fff5fbff910 
Destructor: 0x7fff5fbff920 
Destructor: 0x7fff5fbff930 

沒有例外,並用更多的代碼它確實會產生正確的答案。但是,它似乎破壞了從未構建過的0x7fff5bff910。請注意,複製構造函數永遠不會被調用,它會打印出一條消息。

+0

您可以確保您發佈了您正在使用的確切代碼。沒有返回類型的'main'應該會產生一個編譯錯誤。 – 2012-02-19 11:50:08

+1

...對於那些認爲在NULL上調用'delete []'是錯誤的人:**「在任何一種替代[delete和delete []]中,如果delete的操作數的值是空指針,則操作沒有任何效果。「** – LihO 2012-02-19 12:01:18

回答

1

保利創造了3次Poly a;的主。 Poly c;fun()。並且在分配函數的結果之前。所以有3個析構函數。

這種行爲是確定的,但某些編譯器可能會優化此過程。

+2

我不會調用程序的行爲不行,還有_undefined behavior_。 – 2012-02-19 12:01:31

6

它看起來像你的「保利運營商=」不返回任何東西。

+0

謝謝!這解決了這個問題。 – Ekalavya 2012-02-19 12:02:54

+0

不客氣。 – innochenti 2012-02-19 15:10:59

0

在此代碼:

Poly fun(){ 
Poly c; 
return c; 
} 
... 
Poly a; 
a = a.fun(); 

沒有返回值優化:

  1. 一個創建
  2. c爲創建的C
  3. 副本創建
  4. c的破壞
  5. 將c的副本分配到
  6. 的C拷貝被破壞
  7. 被破壞

與返回值優化:創建

  1. 一個創建
  2. Ç
  3. C分配到
  4. c的破壞
  5. 一個是DES tructed

還要注意的是operator=應該是這樣的:

Poly& operator=(const Poly& rhs){ 
    cout << "Executed assignment. " << this << " = " << &rhs << endl; 
    return *this; 
} 

我建議你使用std::vector,而不是一個簡單的數組。我還建議您使用double而不是float。如果你聲明coeff是這樣的:std::vector<double> coeff;那麼你不需要爲它分配內存,你不需要明確地初始化它,你也不需要刪除它。

+0

非常感謝!這是一個超級社區。 – Ekalavya 2012-02-19 11:41:22

+0

@ user1219083:不客氣;) – LihO 2012-02-19 11:42:19

+2

'operator ='應該總是返回一個非const引用來與[兼容標準容器](http://stackoverflow.com/questions/2969387/why-operator-returns-reference -not const的參考)。 – 2012-02-19 12:08:14

2

主要問題是在賦值運算符。它返回Poly by value,但您從不指定任何內容。

所以,在這一行a = a.fun();我們得到新的Poly作爲operator=的結果。這個臨時變量立即退出範圍,因此它的析構函數被調用。但是,因爲你沒有從operator =返回一些東西,所以暫時還沒有建成。

我建議您在編譯時使用-Wall參數gcc打開所有警告,並返回參考operator=,而不是臨時的。

+0

我喜歡這個解釋。哇!謝謝。 – Ekalavya 2012-02-19 12:20:15

3

你的程序有兩個實際的錯誤。首先是main需要聲明爲返回int

第二個問題是您的複製賦值運算符未聲明爲返回void,但控制權在不執行return語句的情況下離開該函數。這導致未定義的行爲,因此您看到的不可預測的影響。


幾乎可以確定你想要你的拷貝賦值運算符的價值,並return *this;返回一個參考,而不是一個對象。雖然技術上你可以按價值歸還任何物品,但它會是非常傳統的。

顯然,你的拷貝構造函數和拷貝賦值操作符還沒有在實現中做任何有用的拷貝,但我認爲這是因爲代碼是用於測試或「尚未實現」的。