2013-11-24 1 views
1

Я реализовал кучу, используя два класса под названием IndexedHeap и HeapEntry. У меня есть поврежденный доступ к памяти, вызывающий segfaults, и я считаю, что знаю, где и почему, но я не уверен, как это исправить. Вот как я разработал классы до сих пор:Стратегия управления памятью с двумя путями в двух направлениях

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) 
    {} 
}; 

Как куча, так и ее записи должны ссылаться друг на друга. Как вы можете видеть, я решил использовать необработанный указатель на IndexedHeap в HeapEntry. Здесь я думаю, что поступил неправильно, но я не уверен.

В ходе выполнения программы новые записи кучи создаются как часть одной кучей. Записи также удаляются из этой кучи и уничтожаются. Возможно, когда одна запись кучи будет уничтожена, куча, на которую указывает она, будет повреждена. Это объясняет мои проблемы с памятью, поскольку в следующий раз, когда запись кучи пытается получить доступ к своей куче, она обращается к освобожденной памяти.

К сожалению, я не уверен в этом. Я не реализовал деструктор для 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

Как распределяется HeapEntry и как он должен освобождаться? Как вы убедитесь, что у кого-то нет указателя на уже освобожденный HeapEntry? Использование простого старого указателя в классе STL-контейнера является верным билетом для повреждения памяти, если STL-контейнер участвует в освобождении вашего указателя. Вы должны пойти и прочитать о умных указателях. –

+0

Ну, почему вы не используете приоритетную очередь из STL или используете мультимап в качестве очереди приоритетов? Это лучшее решение, чем писать свои собственные. – RichardPlunkett

+0

Я не слишком хорошо знаком с умными указателями, поэтому я обязательно прочитаю их и попытаюсь посмотреть, где они могут помочь.Теперь я также отредактирую вопрос, чтобы включить код, который создает и уничтожает записи кучи. – yan

ответ

1

Ну, во-первых, почему вы ARENT с использованием очереди приоритета из STL, или с использованием Multimap как очереди приоритетов? Это лучшее решение, чем писать свои собственные.

Далее, код структуры: std::vector<HeapEntry*> heap; известен как утечка памяти, при этом люди не удаляют указанную память, а также при возникновении серьезных сбоев памяти, когда люди пытаются удалить указанную память и ошибочно удалить это.

"IndexedHeap* myHeap;", скорее всего, не ваша проблема. Ссылки на то, что вам не принадлежит, могут быть проблемой, если кто-то удалит эти объекты, но, скорее всего, вы прекратили использовать th записей к тому времени. Btw, так как его ссылка, вы должны рассмотреть возможность сделать ссылку (которая затем привязана во время ctr и никогда не менялась), но это все равно изменит безопасность кода. Как вы полагаете, dtr для указателя ничего не делает для цели.

Можете ли вы запустить valgrind? он очень быстро решает такие вещи. Else:

Не пытайтесь удалить любые записи и посмотрите, не прекратит ли это ваши ошибки, если это так.

Вы также можете попробовать отслеживать указатели, которые вы новичок и удалить, либо отпечатками, либо глобальным объектом set/map. Это может быть удобно найти эти вещи.

+0

Я строю свое, потому что у него есть некоторые дополнительные функции. А именно, чтобы иметь возможность удалять запись из середины кучи, повторно убивать и поддерживать порядок кучи. Я не знаю о существовании такой кучи. Я использую gcc с mingw, поэтому valgrind не вариант. На данный момент я попробую несколько советов по отладке. – yan

+0

Хорошо, я подозреваю, что мультимап может поддерживать многие из вас, вы хотите, чтобы вы там были. Он defintely позволяет удалить (что я согласен с типом очереди приоритетов). Хотя, возможно, определение, прохождение вокруг, ссылки на записи могут быть немного сложными. – RichardPlunkett

+0

Еще одно предложение: вы можете написать функцию 'validate()', которая проходит через все дерево и проверяет, являются ли операторы инвариантов по-прежнему истинными (указатели назад и вперед верны, номера индексов верны и т. Д.). Если результатом является то, что дерево попадает в недопустимое состояние, вы можете вызвать эту функцию проверки из нескольких мест в вашем коде, чтобы узнать, где состояние повреждено. –

Смежные вопросы