2015-11-04 206 views
0

所以我有一個結構指針數組。它看起來像這樣:從指針數組中刪除元素 - C++

index     [0 1 2 3 4] 
value of structure  21 7 42 30 NULL 

我試圖刪除存儲在索引2(42)的值。我認爲,因爲這個數組的每個 元素都是一個指向結構體的指針,那麼爲了刪除42, ,我必須先在arr [2]上調用delete,然後我會說arr [2] = arr [3 ] ,然後在arr [3]上使用delete,然後arr [3] = arr [4]。 這是不工作,所以我只是決定嘗試沒有delete關鍵字,只是做arr [2] = arr [3]和arr [3] = arr [4],它的工作。 所以我的問題是,爲什麼我不必使用delete關鍵字來做到這一點。我在想,如果我只是將arr [2]設置爲arr [3],那麼arr [2]指向的結構將會丟失,並且會導致內存泄漏。情況並非如此嗎?

+0

改爲使用'std :: vector'。從矢量中刪除要刪除的指針,然後[擦除](http://en.cppreference.com/w/cpp/container/vector/erase)。 –

+0

其實,我試圖從學校學習一個概念,所以我需要這樣做。 –

+0

請記住回來接受你認爲對你最有幫助的答案。它有益於你,海報和整個社區。 – ray

回答

1

我認爲,因爲此數組中的每個元素是一個指針,指向的結構,則爲了刪除42,我必須先調用刪除ARR [2]

是的,你將在arr[2]上使用delete以釋放arr[2]指向的內存。

那麼我會說ARR [2] = ARR [3]

到目前爲止好。

,然後改編刪除[3]

這是問題就在這裏。假設你有這樣的代碼:

int arr_cnt = 5; 
int *arr[arr_cnt]; 
for(int i = 0; i < arr_cnt; ++i) 
    arr[i] = new int(i+arr_cnt); // using ints for simplicity, but concept is the same 

你的陣列arr現在看起來是這樣的:

idx *arr[]  values in heap, due to using 'new' operator 
    +-----+ 
0 | a---|----> 5 
    +-----+ 
1 | b---|----> 6 
    +-----+ 
2 | c---|----> 7 
    +-----+ 
3 | d---|----> 8 
    +-----+ 
4 | e---|----> 9 
    +-----+ 

其中字母代表了new返回不同的內存地址。

這意味着,在指數2正常刪除的元素,你需要:

  1. arr[2]使用delete,以避免內存泄漏,
  2. 覆蓋arr[2]與這仍然有效一些其他的地址(使用arr[2]現在會觸發段錯誤)
  3. 無效陣列位置複製到arr[2](見下文)
  4. 遞減數組的長度(例如arr_cnt--;

換句話說:

delete arr[2];  // step 1, address 'c' no longer valid 
arr[2] = arr[4]; // step 2, arr[2] is now 'e', which points to 9 just like arr[4] 
arr[4] = NULL;  // step 3, arr[4] is now invalid 
--arr_cnt;   // step 4 

現在,該圖是這樣的:

idx *arr[]  values in heap, due to using 'new' operator 
    +-----+ 
0 | a---|----> 5 
    +-----+ 
1 | b---|----> 6 
    +-----+ 
2 | e---|-----------+ // address 'e' used to be in arr[4] 
    +-----+   | 
3 | d---|----> 8 | 
    +-----+   | 
4 | nil |  9 <--+ 
    +-----+ 

然後常用3 [3] = ARR [4]。這是行不通的

如果你按照圖中,你可能已經注意到,現在使用delete都意味着你是無效的兩個條目。換句話說,如果我們跳過第二個圖,並嘗試delete arr[2]; arr[2] = arr[3]; delete arr[3]邏輯,你結束了:

delete arr[2]; 
    +-----+ 
0 | a---|----> 5 
    +-----+ 
1 | b---|----> 6 
    +-----+ 
2 | c---|----> ? // invalidated 
    +-----+ 
3 | d---|----> 8 
    +-----+ 
4 | e---|----> 9 
    +-----+ 

arr[2] = arr[3]; 
    +-----+ 
0 | a---|----> 5 
    +-----+ 
1 | b---|----> 6 
    +-----+ 
2 | d---|-+ 
    +-----+ | 
3 | d---|-+--> 8 // both have the same address, so point to the same place 
    +-----+ 
4 | e---|----> 9 
    +-----+ 

delete arr[3]; 
    +-----+ 
0 | a---|----> 5 
    +-----+ 
1 | b---|----> 6 
    +-----+ 
2 | d---|-+ 
    +-----+ | 
3 | d---|-+--> ? // both invalid now, but not set to null 
    +-----+ 
4 | e---|----> 9 
    +-----+ 

所以我決定嘗試沒有刪除關鍵字,只是不常用3 [2] = ARR [3]和arr [3] = arr [4],並且工作。

但現在你有內存泄漏。你總是要deletenew在C++中,就像你總是要freemalloc在C.

所以我的問題是,爲什麼我沒有使用delete關鍵字才能做到這一點。

必須使用它。問題在於你的失效比你想像的要多,最終試圖與已被釋放的內存一起工作。當程序嘗試像這樣訪問內存時,會導致分段錯誤。我不記得Windows會顯示的確切消息,但它可能是某種未處理的異常消息。 (分割錯誤往往是GNU/Linux術語。)

我在想,如果我只是將arr [2]設置爲arr [3],那麼arr [2]指向的結構將會丟失,我會得到一個內存泄漏。情況並非如此嗎?

你在這裏是正確的。問題不在於你對new/delete關係的理解,只是你描述的任務是副本,並且最終刪除了超過預期的結果。

0

檢查以確保您確實擁有一組結構指針。另外,如果在刪除索引2處的元素後確實有一個結構指針數組,則不要調用3上的delete或之後的索引。只是arr [2] = arr [3]; arr [3] = arr [4];這不是內存泄漏,因爲您只是將指針複製到結構而不是實際結構。

struct A 
    { 
    }; 


//This is an array of A structures 
A * array1; 

//This is an array of pointers to A structures 
A** array2; 
0

我必須先調用刪除ARR [2],然後我會說ARR [2] = ARR [3],然後在ARR刪除[3],則常用3 [3] = ARR [4]。

您需要簡單地刪除arr[2]和所有物品轉移到左側,而不刪除它們。如果您將delete應用於所有相應的對象,則您將全部鬆開。

當然,您可以簡單地移動數組而不刪除arr[2],但這會導致內存泄漏。該物體不會被丟棄。

0

您遇到的問題是您刪除了不應刪除的指針。

後您刪除索引2老指針,並分配在索引3索引2,你有指針指向同一個對象:和指向索引3索引2 3.刪除對象刪除兩個指針指向的對象,使索引2中的指針無效。

的解決問題的方法(除了切換到std::vector這是我的建議)是刪除索引2的第一個對象,該值從更高的指標(如array[2] = array[3])向下移動,最後指針設置爲nullptr。不再需要刪除。