2011-02-04 45 views
3

以下代碼僅用於說明我的問題。顯式析構函數

template<class T> 
class array<T> 
{ 
public: 
    // constructor 
    array(cap = 10):capacity(cap) 
    {element = new T [capacity]; size =0;} 

    // destructor 
    ~array(){delete [] element;} 
    void erase(int i); 
    private: 
     T *element; 
     int capacity; 
     int size; 
}; 



template<class T> 
void class array<T>::erase(int i){ 
    // copy 
    // destruct object 
    element[i].~T(); //// 
    // other codes 
} 

如果我有array<string> arr在main.cpp中。當我使用erase(5)時,element[5]的對象被破壞,但是element[5]的空間不會被釋放,我可以使用element[5] = "abc"在這裏放置一個新值嗎?或者我是否必須使用貼裝新功能將新的價值放在element [5]的空間中?

程序結束時,arr<string>將調用它自己的析構函數,該函數也調用delete [] element。因此,字符串的析構函數將運行以首先銷燬該對象,然後釋放該空間。但是因爲我已經明確地破壞了element[5],那麼析構函數(被arr的destuctor調用)運行兩次以破壞element[5]?我知道這個空間不能被釋放兩次,這個對象怎麼樣?我做了一些測試,發現它看起來很好,如果我只是破壞對象兩次而不是釋放空間兩次。

更新

的答案是:

(1)I have to use placement new if I explicitly call destructor.

(2) repeatedly destructing object is defined as undefined behavior which may be accepted in most systems but should try to avoid this practice.

+1

這是一個不好的方法。調用析構函數兩次爲未定義的行爲,其中「看起來很好」是完全可以接受的結果。不過,這並不好。無論如何,儘管陣列中的「擦除」對我來說毫無意義。 – GManNickG 2011-02-04 02:03:02

+1

我同意@GMan:從數組中刪除元素意味着什麼?你想模仿C++`std :: vector`實現嗎?如果是這樣,你是否將刪除元素之後的所有元素移動到「填充空洞」? – 2011-02-04 02:05:42

+0

@ Gman:「擦除」對我來說也沒什麼意義。 – Sean 2011-02-04 02:22:04

回答

6

您需要使用與放置新的語法:

new (element + 5) string("abc"); 

element[5] = "abc"將是不正確的;這將調用 element[5],這不是一個有效的對象,產生未定義的行爲。

程序結束時,arr<string>將調用其自身的析構函數,該函數也稱爲delete [] element

這是錯誤的:您將最終調用已析構函數已被調用的對象的析構函數(例如,上述示例中的elements[5])。這也產生未定義的行爲。

考慮使用std::allocator及其接口。它使您可以輕鬆地將施工分配與施工分開。它由C++標準庫容器使用。

2

只是爲了進一步UD究竟如何可能咬你解釋....

如果erase()一個元素 - 明確調用析構函數 - 那析構函數做這樣的事情遞減引用計數器+清理,刪除指針等等。當你的數組解析器然後做一個delete[] element,它將依次調用每個元素上的析構函數,而對於被擦除的元素,這些析構函數可能會重複引用計數維護,指針刪除等,但是這次是初始化狀態並不像他們期望的那樣,他們的行爲很可能會使程序崩潰。因此,正如Ben在他對詹姆斯的回答的評論中所說的那樣,在數組的析構函數被調用之前,你絕對必須用一個已擦除的元素 - 使用放置新元素 - 取代,因此析構函數將有一些合法的狀態,破壞。

說明這一問題的T最簡單的類型是:

struct T 
{ 
    T() : p_(new int) { } 
    ~T() { delete p_; } 
    int* p_; 
}; 

這裏,p_值由new設置將一個erase()期間被刪除,並且如果不變時~array()運行。要解決這個問題,必須將p_更改爲delete~array()之前有效的內容 - 以某種方式將其清除爲0或由new返回的另一個指針。最明智的做法是放置new,它將構建一個新對象,獲取p_的新有效值,覆蓋舊的無用內存內容。也就是說,你可能會認爲你可以構造重複析構函數是安全的類型:例如,在delete後面設置p_爲0。這可能在大多數系統上都能正常工作,但我很肯定標準中說有兩次調用析構函數是UD。