So, for class I'm (constantly re-inventing the wheel) writing a bunch of standard data structures, like Linked Lists and Maps. I've got everything working fine, sort of. Insertion and removal of data works like a charm.
But then main ends, my list is deleted, it calls it's dtor and attempts to delete all data inside of it. For some reason, this results in a double free event.
All data is inserted into the list by these methods:
/*
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));
};
The first method assumes that it owns the data passed into it; the second copies data passed into it. Now, for main:
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;
}
This results in a stack dump, for a double free event. The list destructor is defined as follows:
/*
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 I comment out either the list destructor or the code in main's if statement, the program runs fine. Now, I'm not sure where this double delete is coming from.
List is destroyed on the end of main, which results in it deleting the data inside of it; which is either owned or copied into it, and only copies ever come out of it (the only time list passes out pointers of it's data is when you remove it from the list).
Obviously, something is created on the stack in main, when parser->getArg('f').getFirst(); is called.
I read this as, (de-ref pointer to parser)->(get a reference of the linked list).(acquire a copy of the first element in list [an std::string]);
Deleting a pointer to parser is no big deal (In fact, I should probably delete that, oops); deleting a reference shouldn't be a big deal either (just a candied up pointer); and deleting a copy of the first element should be a non-issue. Where have I gone wrong? EDIT The code for ListNode is as follows:
/*
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 only ever take pointers to their data, they only ever delete their data when they die with non-null data pointers. The List itself also only ever deletes stuff if it is non-null. All deleted data is set to NULL.
Oh, and the data right now is std::string, I have no control over it's copy constructor, but I would assume it's properly implemented.