2013-03-14 48 views
2

我有一個關於在C++中刪除指針的動態數組的問題。假設我們有以下情況:在C++中刪除指針的動態數組

int n; 
scanf("%d", &n); 
Node **array1 = new Node*[n]; 
/* ... */ 

其中Node是事先定義的特定結構。假設在用new運算符分配之後,我們改變array1的內容(但是我們不會刪除任何東西!)。如果數組中存在重複指針的可能性(無需對它們進行排序或以線性時間插入集合),那麼刪除array1及其所有內容的正確方法是什麼?

+0

數組中的指針本身是否分配在堆上? 如果是這樣,你可以給Node添加一個引用計數,或者可能有另一個只包含指向已分配節點的唯一指針的數組。 – Pete 2013-03-14 20:06:55

+3

爲什麼這個標籤爲C++?如果你使用C++,只需使用矢量。 – none 2013-03-14 20:06:57

+0

你的意思是改變'array1'本身的值,還是其中的指針?你沒有展示如何在代碼中創建'array1'的內容。 – 2013-03-14 20:07:14

回答

3

使用這樣的分配:

Node **array1 = new Node*[n]; 

陣列1的內容是不確定。每個元素是Node*,並且由於內存未初始化,該值可以是任何值。

分配一個指針數組而不是構造指向類的對象。

因此,無論您將哪些指針放入數組中,它們指向的對象都需要在別處構建和銷燬。

因此,要回答你的問題,刪除陣列1的正確方法是

delete[] array1; 

但是,請注意這不會結果在析構函數被調用每個Node* - 你應該處理任何你投入數組之前您刪除數組。

編輯: 我被原來的問題,其中提到的「改變價值」的陣列中,好像有數組中的有效值在你的榜樣分配混淆。

但是......現在我明白你想跟蹤稍後刪除的指針,也許你可以爲此目的創建另一個數組,每個指針只存在一次。因此,您有上面的數組,其中包含指向可能重複的節點的指針,無論您使用什麼目的。然後,您有另一個數組,用於管理刪除的表達目的,其中每個指針只出現一次。應該很容易在pNewNode = new Node()之後設置nodeCleanupArray[i] = pNewNode之類的東西,然後您可以在線性時間內通過該陣列和delete每個元素。 (這意味着你不會打擾檢查array1中的元素,你會依賴nodeCleanupArray進行清理)

+0

非常感謝您的快速和徹底的迴應。但是,如何管理'array1'中的重複指針呢?我不能使用像'std :: vector'或任何其他STL容器這樣的preimplemented動態數據結構,因爲我不允許在我的項目中這樣做。 – zawodny 2013-03-14 20:30:04

+0

太好了,那正是我想要做的。再一次,我對這個問題的解釋缺乏清晰度感到遺憾,但是我之前並沒有對指向C++指針的指針感興趣。謝謝 :) – zawodny 2013-03-14 20:50:55

0

嘗試標記並掃描:)您正在嘗試實施託管環境。

下面是一個例子:

struct Node 
{ 
... 
    bool marked; 

    Node() : marked(false) 
    {} 
}; 

現在刪除:

void do_delete(Node **data, size_t n) 
{ 
    size_t uniq = 0; 
    Node **temp = new Node*[n]; 

    for (size_t i = 0; i < n; i++) 
    { 
     if (data[i] && !data[i]->marked) 
     { 
      data[i]->marked = true; 
      temp[uniq++] = data[i]; 
     } 
    } 

    for (i = 0; i < uniq; ++i) 
    { 
     delete temp[i]; 
    } 

    delete[] temp; 
    delete[] data; 
} 
0

我這樣做的方式是有一個引用計數器並且有一個Node :: deref方法當引用計數爲0時刪除節點本身。在迭代節點列表時,調用node-> deref將不會實際刪除對象,直到數組中的最後一個節點引用。

1

有這一類的問題,許多解決方案,但最明顯的選擇是去改變它使用

std::vector< std::shared_ptr<Node> > 

現在你將有一個引用計數指針,而無需編寫任何代碼,「陣列「這並不需要知道它是預定義的大小。

您當然可以在Node或您自己的容器對象中實現一個引用計數對象來執行相同的操作,但這看起來像是額外的麻煩,很少或沒有任何好處。

0

什麼是刪除

您展現一個分配陣列1及其所有內容的正確方法; new Node*[n]。該分配賦予程序撥打delete [] whatever_the_return_value_was的責任。這只是關於刪除一個分配而不是刪除「所有內容」。如果您的計劃執行其他分配,那麼計劃也需要安排這些責任進行處理。

如果有重複的指針數組中的可能性

那麼這將是不確定的行爲delete不與任何當前分配相關聯的指針值,所以你要避免刪除相同的指針值不止一次。這不是存在單一正確方式的問題,而是編程實踐,設計等問題。

通常C++使用RAII來自動處理這些東西,而不是嘗試手動執行所需的操作,因爲它手工操作確實很難得到正確的結果。在這裏使用RAII的一種方法是擁有「擁有」節點的第二個對象。您的array1然後將簡單地使用原始指針作爲「非擁有」指針。然後刪除所有節點將通過讓Node擁有的對象超出範圍或以其他方式被銷燬來完成。

{ 
    // object that handles the ownership of Node objects. 
    std::vector<std::unique_ptr<Node>> node_owner; 

    // your array1 object that may hold repeated pointer values. 
    std::vector<Node*> array1; 

    node_owner.emplace_back(new Node); // create new nodes 

    array1.push_back(node_owner.back().get()); // put nodes in the array 
    array1.push_back(node_owner.back().get()); // with possible duplicates 

    // array1 gets destroyed, but it's contents do not, so the repeated pointers don't matter 
    // node_owner gets destroyed and destroys all its Nodes. There are no duplicates to cause problems. 
} 

而且銷燬確實發生在線性時間。