Итак, для класса я (постоянно изобретаю колесо) пишу набор стандартных структур данных, таких как связанные списки и карты. У меня все работает нормально, вроде. Вставка и удаление данных работает как брелок.
Но затем основной заканчивается, мой список удаляется, он вызывает его dtor и пытается удалить все данные внутри него. По некоторым причинам это приводит к двойному бесплатному событию.
Все данные вставляются в список следующими способами:
/*
Adds the specified data to the back of the list.
*/
template<typename T, class COMPFUNCTOR>
void List<T, COMPFUNCTOR>::append(T* d)
{
if(tail != NULL)
{//If not an empty list, simply alter the tail.
tail->setNext(new ListNode<T>(d));
tail = tail->getNext();
}
else
{//If an empty list, alter both tail and head.
head = tail = new ListNode<T>(d);
}
size++;
};
/*
Adds a copy of the specified data to the back of the list.
*/
template<typename T, class COMPFUNCTOR>
void List<T, COMPFUNCTOR>::append(const T& d)
{
this->append(new T(d));
};
Первый метод предполагает, что он владеет данными, переданными в него; второй копирует данные, переданные в него. Теперь для основного:
int main(int argc, char** argv)
{
parser = new Arguments(argc, argv); //Uses a map<char, list<string>>; no direct bugs, insertion works fine.
if(parser->flagSet('f'))
{
printf("%s\n", parser->getArg('f').getFirst().str.c_str());
}
return 0;
}
Это приводит к дампу стека для события с двойным освобождением.
Деструктор списка определяется следующим образом:
/*
Destroys the List and all data inside it.
*/
template<typename T, class COMPFUNCTOR>
List<T, COMPFUNCTOR>::~List()
{
while(head != NULL)
{
ListNode<T>* tmp = head; //Set up for iteration.
head = head->getNext();
if(tmp->getData() != NULL) //Delete this node's data then the node itself.
delete tmp->getData();
delete tmp;
}
};
Если я закомментирую либо деструктор списка, либо код в операторе if оператора main, программа будет работать нормально. Теперь я не уверен, откуда приходит это двойное удаление.
Список уничтожается в конце main, что приводит к удалению данных внутри него; который либо принадлежит, либо скопирован в него, и из него когда-либо выходят только копии (единственный раз, когда список пропускает указатели своих данных, это когда вы удаляете его из списка)
Очевидно, что что-то создается в стеке в main, когда
. Parser-> getArg ( 'е') GetFirst (); называется.
Я читаю это как,
(указатель де-реф на парсер) -> (получить ссылку на связанный список). (получить копию первого элемента в списке [an std :: string]);
Удаление указателя на синтаксический анализатор не представляет особой проблемы (на самом деле, мне, вероятно, следует это удалить, упс); удаление ссылки тоже не должно быть большим делом (просто прикованный указатель); и удаление копии первого элемента не должно быть проблемой. Где я ошибся?
EDIT
Код для ListNode выглядит следующим образом:
/*
Create a ListNode with the specified neighbor.
*/
template<typename T>
ListNode<T>::ListNode(T* d, ListNode<T>::ListNode* neighbor)
{
data = d;
next = neighbor;
}
/*
Deletes the ListNode.
*/
template<typename T>
ListNode<T>::~ListNode()
{
next = NULL;
if(data != NULL)
delete data;
data = NULL;
}
ListNodes только когда-либо получают указатели на свои данные, они только удаляют свои данные, когда они умирают с ненулевыми указателями данных. Сам список также всегда удаляет материал, если он не равен нулю. Все удаленные данные имеют значение NULL.
Да, и сейчас данные - это std :: string, я не могу контролировать их конструктор копирования, но я бы предположил, что он правильно реализован.