2012-08-09 101 views
0

我在C++ quiz過這個問題(初學C++):我的答案是不正確的,我想知道正確的答案背後的解釋 - 「未定義行爲」這個C++測驗答案背後的解釋是什麼?

問: 後會發生下面的代碼是什麼函數foo()返回?

class base 
{ 
    public: 
     base() { } 
     ~base() { } 
}; 

class derived : public base 
{ 
    private: 
     int *p_pi_values; 

    public: 
     derived() : p_pi_values(new int[100]) { } 
     ~derived() { delete [] p_pi_values; } 
}; 

void foo(void) 
{ 
    derived *p_derived = new derived(); 
    base *p_base = p_derived; 

    // Do some other stuff here. 

    delete p_base; 
} 

我給了這個答案,結果出錯==>整數數組將不會被正確刪除。

Correct Answer ==>行爲是未定義的。

+0

這可能有助於http://stackoverflow.com/questions/5392590/destructor-in-c – silvesthu 2012-08-09 22:02:17

回答

9

你基類的析構函數不是virtual。這只是語言規則,如果通過指向基礎子對象的指針刪除對象,則相應的基類必須具有虛擬的des,否則它是未定義的行爲。 (實際上,如果你的基類沒有虛析構函數,編譯器可能不會發出必要的代碼來執行衍生對象的所有必要的清理工作,它只會假設你的對象是與指針相同的類型,並且不打算進一步查看,因爲實際上多數派生對象的多態查找的代價是您不希望施加不必要的代價。)

§5.3.5/ 3:

在第一種替代方法(刪除對象)中,如果操作數的靜態類型與其動態類型不同pe,靜態類型應該是操作數動態類型的基類,而靜態類型應該具有虛擬析構函數或行爲不明確

+0

一個標準的報價來支持這將是很好的;我最後一次試圖在那裏查看它,它既不明確也不清楚... – PlasmaHH 2012-08-09 22:08:44

+0

@PlasmaHH它是常識:) – 2012-08-09 22:12:01

+0

@LuchianGrigore:如果是,那麼我們需要什麼標準呢? – PlasmaHH 2012-08-09 22:12:24

2

您應該使您的析構函數在基類中變爲虛擬。現在代碼的問題是delete p_base將導致基類的析構函數被調用。派生類中的一個不會被調用,並且爲整數數組分配的內存不會被釋放。

發生這種情況是因爲如果某個方法在基類中不是虛擬的,編譯器只會查看一個指針類型並調用位於此類型中的方法(在這種情況下 - 它是基類),即決定使用哪種方法在編譯時根據指針的類型進行調用,而不是指針所指對象的實際類型。

-3

我想編譯器可以優化這段代碼,因此p_derived從未分配給p_base。

更具體地說,編譯器可以將代碼優化爲一行。

刪除new derived();

因此,它被視爲未定義的行爲可以改變編譯器真正優化代碼的方式。

+0

這與優化無關。 – 2012-08-09 22:39:01

0

出於好奇我檢查C++規格。問題的答案是第5.3節中的第3項。5:

在第一個替代(刪除對象),如果靜態類型要被刪除的 對象的是二FF erent從它的動態型,靜態 類型應是基類的動態類型的的刪除對象爲 ,靜態類型應具有虛擬析構函數或 行爲未定義。

就我個人而言,我會以同樣的方式回答您的問題。如果你忽略編譯器的警告,最可能的結果是派生類的析構函數不會被調用。