My "Game Engine" required a container in which insert and remove operations are fairly easy. I chose to go with a doubly linked list. I made it a templated class and I can't get it to work! It's the strangest issue I've ever faced, I insert more than 4 elements and the application hangs. No reponse, I have to exit the console manually in order to terminate it.
I have gone through it several times and I can't seem to find the problem, I even made the list print out a series of debug messages and they're all OK. Perhaps it's just some noobish mistake hiding in the dark, but since my efforts to correct it are useless I hope you'll have better luck than me.
Here's the full source code so far:
I know that I'm missing a lot of important operations here, now. I just didn't want to carry on with this bug.
Sorry to be bothering you with this.
Thanks in advance and best regards,
~Deimos
Your implementation is unusual. It's traditional to maintain a head/tail pointer and only insert data nodes. It's not clear advantage your guard node offers.
Further, your insert method seems to care about the content of the list. A list is expected to store duplicates, yours doesn't.
Are you moving properties from your app into the list, or is this meant to be a standard list.
Well, I suppose that the list I'm implementing will never be as fast as the standard one. I just wanted to do it in order to understand things a little better.
The non duplicates code is specific for my purposes. The idea is a "DisplayList" which will store pointers to all in game sprites and render them according to their position on that same list. I don't want any sprite to be rendered twice, that's where !contains(_data) kicks in.
1. Node( Type, Node* ) constructor does very bad things if the Node* passed in is NULL;
2. ~CLinkedList() first deletes curr, then dereferences it: curr->curr->ptNext;
3. remove() always seems to remove the first node, whether or not it is the one you're looking for;
4. I'm pretty sure your Node( Type, Node* ) constructor does not work in the case where the
list contains more than just a guard node.
Thanks a lot, jsmith. The problem lied within the destructor. Its's funny how a new pair of eyes finds the issue much faster. :D
1. Well, only CLinkedList can access Node objects and since there is always a guard node NULL will never be passed to its constructor.
3. Actually, the method find(Type _data) besides returning the address of the node, stores the found node's address on curr, that's why I reset curr to point to the first node after the deletion. :)
4. Nah, it works perfectly. xD
Again, thanks a lot :)
Best Regards
~Deimos
[EDIT]
I compared the performance of my list with the performance of std::list...one test was all it took:
1. From an engineering point of view, I would argue that functions should work for all inputs. The constructor should not crash if NULL is passed; it should do something sane (perhaps throw an exception).
3. Ah, I missed that. Slightly non-intuitive, IMHO. I'd expect find() to be a const member
function that does not modify the state of the object.
@helios:
I took 'em all out before running the test.
@jsmith:
Yes, I do belive you're right, I could make it throw an exeption. But, since an exeption needs handling, would an assert(_next) statement do the trick?
Well, assert() kills the program; no way to stop it.
An unhandled exception also kills the program, but gives the programmer the flexibility to handle the exception and thus not terminate the application.