mObjects = a std::map
void Node::deleteAllObjects()
{
std::string string;
std::stringstream sstream;
sstream << mObjects.size();
sstream >> string;
MAP_STRING2MOVABLEOBJECT::iterator i, iend;
iend = mObjects.end();
MessageBox(NULL,string.c_str(),"Size of mObjects",MB_OK);
for (i = mObjects.begin(); i != iend; ++i)
{
///i->second->setParent(0);
MessageBox(NULL, "Node::deleteAllObjects() called", mName.c_str(),MB_OK);
delete i->second;
//i->second->_notifyDetachment();
}
mObjects.clear();
}
🔒 Locked
Problem with std::map
Advertisement
Original Post
Hi, I am having some trouble with this section of code because it seems to be causing a memory read error. I am not sure what the problem is. Here is my code. Now ill tell you kinda what the message boxs say in order Size of mObjects = 1 Node::deleteAllObjects() called (now the destructor of the object is a called displaying its name in a msgbox) Node::deleteAllObjects() called ; im not sure why its doing this again now I get the error because im trying to access and invalid i->second address. Please help me spot what im doing wrong. Note: I have tried to do this without attatching an object to this node and no errors happen [Edited by - starfleetrp on August 14, 2006 3:56:25 PM]
Write:
Now, in that loop, do the following::
What do you get?
Second, can you sketch what i->second does in it's destructor?
template<typename any_map_type>void MsgBoxNumOfObjects( any_map_type const& Objects ) { std::string string; std::stringstream sstream; sstream << Objects.size(); sstream >> string; MessageBox(NULL,string.c_str(),"Size of map",MB_OK);}Now, in that loop, do the following::
for (i = mObjects.begin(); i != iend; ++i) { MsgBoxNumOfObjects(mObjects); ///i->second->setParent(0); MessageBox(NULL, "Node::deleteAllObjects() called", mName.c_str(),MB_OK); delete i->second; MsgBoxNumOfObjects(mObjects); //i->second->_notifyDetachment(); }What do you get?
Second, can you sketch what i->second does in it's destructor?
Ok well the mObjects contains a pointer to a *MovableObject in second
so the ~MovableObject is just:
{
MessageBox(NULL,mName.c_str(),"~MovableObject ",MB_OK);
}
which is called when the MovableObject is deleted
and oh yeah the Nodes destructor calles the deleteObjects function
Now with your modifications to the loop I now get....
~Node "Ship Hull "
Node::deleteObject Called "Ship Hull"
Map Size 1
~Movable Object Ship1 Entity
Map Size 0
Node::deleteObject Called "Ship Hull"
Map Size 0
ERROR
-- The done with call messagebox does not show up (newly added)
note I also changes a bit of the function besides the loop. I got rid of the inital Objects size and move up the deleleObject messagebox so now its like
so the ~MovableObject is just:
{
MessageBox(NULL,mName.c_str(),"~MovableObject ",MB_OK);
}
which is called when the MovableObject is deleted
and oh yeah the Nodes destructor calles the deleteObjects function
Now with your modifications to the loop I now get....
~Node "Ship Hull "
Node::deleteObject Called "Ship Hull"
Map Size 1
~Movable Object Ship1 Entity
Map Size 0
Node::deleteObject Called "Ship Hull"
Map Size 0
ERROR
-- The done with call messagebox does not show up (newly added)
note I also changes a bit of the function besides the loop. I got rid of the inital Objects size and move up the deleleObject messagebox so now its like
//std::string string; ////std::stringstream sstream; //sstream << mObjects.size(); //sstream >> string; MAP_STRING2MOVABLEOBJECT::iterator i, iend; iend = mObjects.end(); //MessageBox(NULL,string.c_str(),"Size of mObjects",MB_OK); //MsgBoxNumOfObjects(mObjects); for (i = mObjects.begin(); i != iend; ++i) { MessageBox(NULL, "Node::deleteAllObjects() called", mName.c_str(),MB_OK); MsgBoxNumOfObjects(mObjects); ///i->second->setParent(0); delete i->second; MsgBoxNumOfObjects(mObjects); //i->second->_notifyDetachment(); } MessageBox(NULL,"Done with the call","",MB_OK); mObjects.clear();
And finally:
Deleting a movable object changes the size of your map!
I do not believe:
that "delete i->second" only executes the above code. What is the class heirarcy of a MovableObject? Does it inherit from or contain any classes with non-trivial destructors? Is the destructor virtual, and does anything inherit from it that contains non-trivial destructors?
Does any of the above destructors "automatically remove itself from the map, to be safe"?
However you are doing it -- either explicitly, or accidentally via memory corruption (unlikely, honestly) -- you are invalidating your iterator by removing the node from the map while you are iterating over it.
This makes "++i" execute undefined behaviour -- you are not allowed to use an invalidated iterator. The undefined behaviour, in this case, happens to be "I give you an invalid pointer when you call i->second".
Quote:
Map Size 1
~Movable Object Ship1 Entity
Map Size 0
Deleting a movable object changes the size of your map!
I do not believe:
Quote:
Ok well the mObjects contains a pointer to a *MovableObject in second
so the ~MovableObject is just:{MessageBox(NULL,mName.c_str(),"~MovableObject ",MB_OK);}
which is called when the MovableObject is deleted
that "delete i->second" only executes the above code. What is the class heirarcy of a MovableObject? Does it inherit from or contain any classes with non-trivial destructors? Is the destructor virtual, and does anything inherit from it that contains non-trivial destructors?
Does any of the above destructors "automatically remove itself from the map, to be safe"?
However you are doing it -- either explicitly, or accidentally via memory corruption (unlikely, honestly) -- you are invalidating your iterator by removing the node from the map while you are iterating over it.
This makes "++i" execute undefined behaviour -- you are not allowed to use an invalidated iterator. The undefined behaviour, in this case, happens to be "I give you an invalid pointer when you call i->second".
Ok the MovableObjects destructor is virtual and the object that is inherieted is an *Entity. The entity destructor is also virtual but does nothing at the moment.
Edit: I dont know I just did a re-build of the whole project instead of a build and now it works. Something must have been really messed up with VC++.
Edit: I dont know I just did a re-build of the whole project instead of a build and now it works. Something must have been really messed up with VC++.
It seems to me as if you don't know how to use the debugger. All those calls to MessageBox gives it away :-)
You should instead set a breakpoint at the points where you want to inspect variables. When the code stops, just look at them in the Auto window (or type their name into the Watch window). Also, stepping line by line with F10 (and into functions with F11) is very useful when figuring out what's going wrong, especially combined with breakpoints in object destructors. (Unfortunately, F11 doesn't work for stepping into a deleted objects destructor, due to a bug in VS 2003 and 2005)
You should instead set a breakpoint at the points where you want to inspect variables. When the code stops, just look at them in the Auto window (or type their name into the Watch window). Also, stepping line by line with F10 (and into functions with F11) is very useful when figuring out what's going wrong, especially combined with breakpoints in object destructors. (Unfortunately, F11 doesn't work for stepping into a deleted objects destructor, due to a bug in VS 2003 and 2005)
I was using the messageboxs so I could see the objects name instead since every one has its own indivvidual name. This way it is better than a break point because I can see what object was messing up.
[Edited by - starfleetrp on August 14, 2006 11:43:55 PM]
[Edited by - starfleetrp on August 14, 2006 11:43:55 PM]
As an aside:
Some delete functions return iterators one past the element you just deleted. ie:
for(iter = container.begin(); iter != container.end(); /* do nothing here */ )
{
if(blah)
iter = container.delete(iter); // delete element and move to next valid element
else
iter++; // ignore element and move to next valid element
}
Some delete functions return iterators one past the element you just deleted. ie:
for(iter = container.begin(); iter != container.end(); /* do nothing here */ )
{
if(blah)
iter = container.delete(iter); // delete element and move to next valid element
else
iter++; // ignore element and move to next valid element
}
Quote:
I was using the messageboxs so I could see the objects name instead since every one has its own indivvidual name. This way it is better than a break point because I can see what object was messing up.
In other words, you don't know how to use the debugger? You can use the "watch window" to examine the contents of variables, including the individual name of the individual object. Also, you can use tracepoints instead of Messageboxs to get essentially the same result as "MessageBox debugging" without having to recompile your code. I suggest you spend some time exploring the features of your debugger because it is an essential tool to know.
Of course, this assumes you are using an IDE with a decent debugger (Visual Studio) and not some terrible broken debugger like the one with Dev-C++.
Your right, I did not know about the "watch box" and for some reason I can not even seem to find the window. I know I sound pretty stupid (im sure I also am). I tried to google arround for it and the results I found just simply state what is does and how to use it. However that is assuming that I can see it, which I cant. Can someone please tell me what I am doing wrong. I am using VC++ 2003
Note that using the debugger in 'release' mode can produce unexpted results (breakpoints might be ignored, the debugger will jump the 'currently executing line' all over the place even when single stepping [it might even go backwards such as line 5 then 6 then 7 then 6 then 5 then 8], etc) in VS 2003 and prior (don't know about 2005)
Topic Locked
This topic has been locked by a moderator. New replies are not allowed.
Sign in to reply to this topic.
Advertisement