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
", 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.