2013-11-24 54 views
1

我使用兩個名爲IndexedHeap和HeapEntry的類實現了一個堆。我有一些損壞的內存訪問導致segfaults,我相信我知道在哪裏/爲什麼,但我不知道如何解決它。以下是我迄今爲止設計類的方法:C++雙向關聯內存管理策略

class IndexedHeap 
{ 
private: 
    std::vector<HeapEntry*> heap; // the entries held by this heap 
public: 
    ... 
}; 

class HeapEntry 
{ 
private: 
    int index; 
    size_t priority; 
    unsigned long long key; 
    IndexedHeap* myHeap; // reference to heap where this entry resides 
public: 
    HeapEntry(unsigned long long key, size_t priority, IndexedHeap* myHeap) 
     : key(key), priority(priority), index(-1), myHeap(myHeap) 
    {} 
}; 

堆和它的條目都需要相互引用。正如你所看到的,我決定使用一個原始指針指向HeapEntry中的IndexedHeap。這是我認爲我出錯的地方,但我不確定。

在整個程序執行過程中,都會創建新的堆條目,作爲一堆的一部分。條目也從這堆中刪除並銷燬。也許當一個堆條目被銷燬時,它指向的堆被損壞。這將解釋我的內存問題,因爲下次堆入口嘗試訪問堆時,它將訪問已釋放的內存。

不幸的是,我並不相信這一點。我沒有實現HeapEntry的析構函數。默認的析構函數只是調用一個類的所有實例變量的析構函數?那麼指向myHeap的指針會不會被破壞,而堆對象本身還能存活?

那麼,設計這種關係的正確方法是什麼?我的記憶問題可以從我發佈的代碼中解釋出來嗎?謝謝,請讓我知道你是否想看更多的代碼或更多的細節。

HeapEntry* IndexedHeap::insert(unsigned long long key) 
{ 
    HeapEntry* entry = new HeapEntry(key, 1, this); 
    heap.push_back(entry); 
    int index = heapifyUp(heap.size() - 1); 
    heap[index]->setIndex(index); 
    return entry; 
} 

void IndexedHeap::deleteAtIndex(int pos) 
{ 
    if (pos >= 0 && pos < heap.size()) 
    { 
     // Copy heap.back() into the position of target, thus overwriting it 
     *heap[pos] = *heap.back(); 

     // Fix the index field for the just copied element 
     heap[pos]->setIndex(pos); 

     // We've removed the target by overwriting it with heap.back() 
     // Now get rid the extra copy of heap.back() 
     // Release the mem, then pop back to get rid of the pointer 
     delete heap.back(); 
     heap.pop_back(); 

     // Heapify from the position we just messed with 
     // use heapifyDown because back() always has a lower priority than the element we are removing 
     heapifyDown(pos); 
    } 
} 
+0

HePentry是如何得到分配的,它應該如何被釋放?你如何確保沒有人擁有已釋放HeapEntry的丹靈指針?如果STL容器涉及釋放指針,則在STL容器類中使用普通舊指針是一個確定的內存損壞票據。你應該去看看智能指針。 –

+0

那麼,爲什麼你不使用STL的優先級隊列,或者使用multimap作爲優先級隊列?它比編寫自己的解決方案更好。 – RichardPlunkett

+0

我對智能指針不太熟悉,所以我一定會閱讀它們並嘗試查看它們可以提供的幫助。我現在還要編輯這個問題,以包含創建和銷燬堆條目的代碼。 – yan

回答

1

嗯,首先,你使用STL從優先級隊列,或者使用多重映射爲優先級隊列的arent原因:創建並在堆破壞項

碼?它比編寫自己的解決方案更好。

接下來,代碼結構:std::vector<HeapEntry*> heap;因內存泄漏而臭名昭着,人們沒有刪除指向的內存,而當人們嘗試刪除指向的內存並導致刪除錯誤時導致嚴重的內存故障。

"IndexedHeap* myHeap;"很可能不是你的問題。如果有人刪除了這些對象,那麼對您不擁有的事物的引用可能會成爲問題,但是到那時您可能會停止使用這些對象。順便說一句,既然它是一個引用,你應該考慮把它作爲一個引用(然後在ctr期間綁定並且永遠不會改變) - 但是這會改變代碼的安全性。如你所知,指針的dtr對目標沒有任何影響。

你可以運行valgrind嗎?它很快解決了這樣的問題。否則:

請嘗試不刪除任何條目,並查看是否能夠阻止您的錯誤,如果是的話。

您還可以嘗試跟蹤您新建和刪除的指針,可以通過打印或通過全局設置/地圖對象進行跟蹤。這可以方便地找到這些東西。

+0

我建立我自己的,因爲它有一些額外的功能。也就是說,爲了能夠從堆中間刪除條目,重新堆積並維護堆排序。我不知道這種堆的現有實現。我在使用gcc的windows上使用mingw,所以valgrind不是一個選項。我現在要嘗試一些調試技巧。 – yan

+0

好吧,我懷疑一個multimap可以支持你想要的地方。它defintely允許刪除(我同意優先隊列類型doesnt)。雖然也許識別,傳遞,參考條目可能有點棘手。 – RichardPlunkett

+0

還有一個建議:你可以編寫一個'validate()'函數來遍歷整個樹並檢查不變的語句是否仍然爲真(來回指針是正確的,索引號是否正確等)。如果結果是樹進入無效狀態,則可以從代碼中的幾個地方調用此驗證函數,以查看狀態被破壞的位置。 –