problems remove()ing with std::list

Started by
12 comments, last by GameDev.net 17 years, 9 months ago
To start off, I will describe what I am doing a bit. It may seem a bit irrelevant at the moment, but it might clarify things a bit later. I am using MSVC++ 2005 EE to create a GUI system. I have a Window class which is a standard widget/window/whatever you want to call it. A Window can have child Windows (and, hence, a parent Window). I use an std::list to keep track of which Windows are children of a Window, and a pointer to the parent Window of the Window. Now, when a Window is given input focus, it has the parent Window remove it from the list of child Windows and then add it again. My problem is with the removing of the Window from the child Windows list. I use this function:
void Window::RemoveChild(Window *removedChild)
{
	//childWindows is the std::list
	childWindows.remove(removedChild);
}
However, my program crashes on this line, inside of the remove() call. I get an error message of "list incrementor not incrementable" on line 236 of the list header. Now, this makes me think that removedChild isn't actually inside of remove(). But, I've looked through my code and I can't see how it could not be in there. See, the only way that a child Window can get focus is from a parent Window giving it focus. The only way that RemoveChild() is callled is form a child Window (*parentWindow is checked to be != NULL and I set parentWindow to NULL in the constructor), and it is passed this, so it's not getting the wrong pointer. I've also tried std::find() then erase()ing the found iterator, and writing my own finding algorithm. All of these get the same error that a list iterator cannot be incremented. Well, any suggestions? I don't really know what other code I could possibly show you, since it all _seems_ to be in order. Thanks in advanced.
Advertisement
Quite posibly, the childWindows list most likely has become corrupted. This can happen if you either:
Write out out bounds from some array, or
You have multiple threads modifying this list, without explicit locking around use of the list.
I'm picking the later of these...
"In order to understand recursion, you must first understand recursion."
My website dedicated to sorting algorithms
I only have a single thread running on this program.

As for corrupted, I don't think that that is likely. I use the list in other places(eg: telling the parent window to draw makes it have all the child windows draw, too), and it works there. All that I do to the list is iterate through it for drawing and input handling (should probably use for_each()), push_back() new Windows, and remove() in this problem. I don't use any arrays in my program right now (all strings, lists, or vectors), so writing out of bounds shouldn't be a problem. Is there any way to check for corruption?

I know that iterators can become invalid when you remove it from the list. Could this be a problem? Again, I doubt that it is, seeing as Microsoft almost definately got their remove() implementation correct.

[Edited by - Ezbez on July 6, 2006 4:40:19 AM]
Try doing ++childWindows.begin() in debug mode and see what it does, I suspect it'll do the same thing. Then take a look at the values of childWindows._Myhead and childWindows._Myhead->_Next in the debugger. The only times this should happen without any form of corruption would be if you were trying to increment an empty or end iterator, which can't happen inside remove().
"Voilà! In view, a humble vaudevillian veteran, cast vicariously as both victim and villain by the vicissitudes of Fate. This visage, no mere veneer of vanity, is a vestige of the vox populi, now vacant, vanished. However, this valorous visitation of a bygone vexation stands vivified, and has vowed to vanquish these venal and virulent vermin vanguarding vice and vouchsafing the violently vicious and voracious violation of volition. The only verdict is vengeance; a vendetta held as a votive, not in vain, for the value and veracity of such shall one day vindicate the vigilant and the virtuous. Verily, this vichyssoise of verbiage veers most verbose, so let me simply add that it's my very good honor to meet you and you may call me V.".....V
++childWindows.begin() doesn't cause a crash or error or anything. I don't do anything with this iterator other than increment it; would the problem not show up if I don't do something with the iterator?

And, odly enough, it increments fine even if there is only one child window.
Try:

list<Window*>::iterator i = childWindows.begin();while (i != childWindows.end() {   if (*i == removeChild)       i = childWindows.erase(i);   else       ++i;}


And see what happens
[size="2"]I like the Walrus best.
Quote:Original post by Ezbez
++childWindows.begin() doesn't cause a crash or error or anything. I don't do anything with this iterator other than increment it; would the problem not show up if I don't do something with the iterator?

And, odly enough, it increments fine even if there is only one child window.


Hmm, what's the value of _Myhead? Are you able to follow the _Next pointers in the list nodes using the debugger, and do they contain the correct number of nodes and generally seem to make sense? Since you seem to be dealing with raw pointers you should double check that you haven't accidentally deleted the current this pointer somewhere. Something like this for example:
Window* window = new Window();//...if(window->closed()) delete window;//...window->RemoveChild(child);

It could produce all manner of strange results and could even manifest itself differently with different build configurations. Your description of the process in which this is happenning sounds a bit strange aswell. Why would you remove a child from it's parent and then re-add it when focus changes?
"Voilà! In view, a humble vaudevillian veteran, cast vicariously as both victim and villain by the vicissitudes of Fate. This visage, no mere veneer of vanity, is a vestige of the vox populi, now vacant, vanished. However, this valorous visitation of a bygone vexation stands vivified, and has vowed to vanquish these venal and virulent vermin vanguarding vice and vouchsafing the violently vicious and voracious violation of volition. The only verdict is vengeance; a vendetta held as a votive, not in vain, for the value and veracity of such shall one day vindicate the vigilant and the virtuous. Verily, this vichyssoise of verbiage veers most verbose, so let me simply add that it's my very good honor to meet you and you may call me V.".....V
I remove it then re-add it so that it is at the back of the list and is drawn last, and hence is on top. This was the way that an article about GUIs in DirectX on this website said to do it.

Unfortunately, I'm not really able to debug it. If I try to debug it, it exits before anything happens, and doesn't tell me anything about why. It runs fine without debugging.

I sure hope that I'm not deleting my childWindows. They are on the stack (yes, I know, it shouldn't be that way). I declare both the child and its parent in the main() function, so they should get removed at the same time.

@Owl - This is almost identical to what I tried originally. It crashes, too, with a "list iterator cannot be incremented" error.
Quote:Original post by Ezbez
Unfortunately, I'm not really able to debug it. If I try to debug it, it exits before anything happens, and doesn't tell me anything about why. It runs fine without debugging.


If I was you I'd be sorting this problem out first. It may be a sign that bad things are happenning else and has nothing to do with your Window class. And even if it's not related, debugging without a debugger really sucks.

Quote:I sure hope that I'm not deleting my childWindows. They are on the stack (yes, I know, it shouldn't be that way). I declare both the child and its parent in the main() function, so they should get removed at the same time.


BAD MONKEY!!!! Ahem....try commenting out the offending line(s) of code so that your program can run to completion and see if VS complains about the stack being corrupt or anything similarly nasty (ie. check if you've done bad things to your Window instances while they're on the stack).
"Voilà! In view, a humble vaudevillian veteran, cast vicariously as both victim and villain by the vicissitudes of Fate. This visage, no mere veneer of vanity, is a vestige of the vox populi, now vacant, vanished. However, this valorous visitation of a bygone vexation stands vivified, and has vowed to vanquish these venal and virulent vermin vanguarding vice and vouchsafing the violently vicious and voracious violation of volition. The only verdict is vengeance; a vendetta held as a votive, not in vain, for the value and veracity of such shall one day vindicate the vigilant and the virtuous. Verily, this vichyssoise of verbiage veers most verbose, so let me simply add that it's my very good honor to meet you and you may call me V.".....V
I'm sorry, but I don't quite understand what you mean. Which lines in particular would be the "offending" ones? The declarations of my Windows? Adding the child Windows to the parent Windows? I will test out using new on my Windows, though.

And I'm sorta sure that my problem with debugging comes from using SDL. Would I need to use a special debugging library instead of the typical SDL library?

Edit: some of my debugger output is:

"'OpenGLApplication.exe': Loaded 'C:\Documents and Settings\Owner\Desktop\Tom's Useless Junk\OpenGL Games\Gravitas\Debug\SDL.dll', Binary was not built with debug information."

Along with listing that a bunch of libraries have no symbols loaded (eg: glu32,ntdll, msvcrt, ddraw, many more).

Edit again: Using new for the Windows doesn't change a think, at least as far as I can tell.

This topic is closed to new replies.

Advertisement