2013-01-15 29 views
2

這是一個基於真正問題的構建方案。如果我有一個基類:刪除派生對象時的行爲

class Vehicle 
{ 
public: 
    void run() { incrementStuff(); } 
    virtual void incrementStuff() { } 
}; 

而派生類:

class Car : public Vehicle 
{ 
public: 
    Car() : Vehicle() { stuff = new StuffClass(); } 
    ~Car() { delete stuff; stuff = NULL; } 

    virtual void incrementStuff() { if (stuff != NULL) stuff->increment(); } 

protected: 
    StuffClass* stuff; 
}; 

然後說我有一個要求車輛:: run()的定期線程。我有另一個線程,最終刪除指向汽車的指針。銷燬順序將導致車輛首先被刪除,然後車輛被刪除。

如果線程(生活在Vehicle對象中)調用析構函數在汽車中運行後(但顯然在車輛被破壞之前)調用incrementStuff函數會發生什麼? Car :: incrementStuff是否會被執行並嘗試解引用已經被刪除的指針?或者將調用Vehicle :: incrementStuff,這是安全的,什麼都不做?

假設當Car ::〜Car()正在運行時,線程無法調用Car :: incrementStuff(這是由互斥鎖阻止的)。

此代碼已被重構,以避免這種情況,但我只是想知道是否有人可以闡明這是如何工作的,或者如果它只是普通的未定義行爲?

更一般地說,如果我在Car被破壞之後但在Vehicle之前嘗試致電Car :: incrementStuff,會發生什麼? NULL檢查是否工作,或者內存已經釋放,現在可以被任何東西使用?或者,在基礎對象被破壞之前,內存是不是「釋放」的?

回答

4

你在想這件事。如果您取消引用了已經被delete編輯的指針,則會調用未定義的行爲。這就是你真正需要知道的。只要您致電delete ptr;ptr無效。

同步對此對象的訪問。

6

如果您刪除了Car對象,則後續調用incrementStuff()是未定義的行爲。

順便說一下,您應該在Vehiclevirtual中製作析構函數。請參閱:When to use virtual destructors?

2

一個線程正在讀取一個值,而另一個線程正在寫入它。這是一場數據競賽。如果這兩個操作未正確同步,則行爲未定義。