porting from vc6 to vc2005
#1
Posted 18 March 2006 - 09:03 PM
here's my problem:
i have a GUI library based on windows; all the widgets inherits from a base class; this class has a list of child widgets (a std::vector, actualy), and its destructor also deletes all the widgets children, like this:
if(parent){//remove this kid from the parent's list
std::vector<WinObject *>::iterator it;
for(it=parent->children.begin();it!=parent->children.end();it++)
if((*it)==this){
parent->children.erase(it);
break;
}
}
std::vector<WinObject *>::iterator it=children.begin();
while(children.size()){
delete(*it);
}
While this works perfectly in vc6 and in mingw (gcc 3.4.2) it fails in vc2005 express edition, with a "vector iterator not dereferencable" error. Now, i have no idea, it is vc2005, it is my code?
Thank you for any help.
#2
Posted 18 March 2006 - 11:04 PM
The problem I don't know whether to resolve it, but I have had to abdicate to a project c++ with the vc2005pro and to bring it on vc2003. Too many problems, especially if it has some functions that ask for the directx SDK....
sorry for my bad engrish! :blush:
#3
Posted 18 March 2006 - 11:50 PM
#4
Posted 18 March 2006 - 11:57 PM
std::vector<WinObject *>::iterator it=children.begin(); while(children.size()) delete(*it);I don't even understand why this doesn't generate an infinite loop. The size of the children vector will not decrease if you delete the objects that it points to.
Edit: You don't even increment the iterator in the loop. WTF?
#5
Posted 19 March 2006 - 12:08 AM
it doesnt generate an infinite loop, as there's a parent->children.erase(it); before the code you've quoted.
#6
Posted 19 March 2006 - 04:23 AM
if(parent){//remove this kid from the parent's list
std::vector<WinObject *>::iterator it;
for(it=parent->children.begin();it!=parent->children.end();it++)
if((*it)==this){
parent->children.erase(it);
break;
}
}
std::vector<WinObject *>::iterator it=children.begin();
while(children.size()){
delete(*it);
}
First of all, the loop that tries to remove 'this' from 'parent' isn't guaranteed to work properly because the iterator is invalidated by the call to erase(). And as Axel says, the second loop absolutely doesn't do what it is supposed to. What you probably want is like this:
if (parent)
{
iterator i = parent->children.begin();
while (i != parent->children.end())
if (*i == this) i = parent->children.erase(i); else ++i;
}
iterator i = children.begin(), end = children.end();
for (; i != end; ++i)
delete *i;
Note that erase() invalidates the iterator passed into it, and in a vector it also invalidates all the iterators after it, including end() (and potentially all iterators period, if a reallocation to smaller size occurs). With a list, this wouldn't be a problem. In either case, it returns a valid iterator to the position after the deleted item.
#7
Posted 19 March 2006 - 01:11 PM
here a small program that illustrates my problem:
#include<list>
class Base{
std::list<Base *> children;
Base *parent;
public:
Base(Base *p=0);
~Base();
};
Base::Base(Base *p):parent(p){
if(p)
p->children.push_back(this);
}
Base::~Base(){
std::list<Base *>::iterator i,end;
if (parent){
i = parent->children.begin();
while (i != parent->children.end())
if (*i == this) i = parent->children.erase(i); else ++i;
}
i = children.begin(), end = children.end();
for (; i != end; ++i)
delete *i;
}
int main(){
Base *window, *menu;
window=new Base();
menu=new Base(window);
delete window;
}
the destructor should clean all his children, it does not.
i'd appreciate any help you can give (again)
#8
Posted 19 March 2006 - 05:56 PM
It does NOT clear the vector, so at the end of the destructor it will still contain a list of (no longer valid) pointers to children. But the vector's destructor will take care of this, you don't have to do it yourself.
Also, if you are inheriting anything from Base, you need to make its destructor virtual. Otherwise the derived class's destructor will not be called.
#9
Posted 19 March 2006 - 06:03 PM
#10
Posted 19 March 2006 - 06:15 PM
int main(){
Base *window, *menu,*menitem;
window=new Base();
menu=new Base(window);
menuitem=new Base(menu);
delete menuitem;
delete window;
}
for the earlier version, a destructor like
Base::~Base(){
for(i=children.begin();i!=children.end();++i)
delete *i;
}
would do.
thanks.
#11
Posted 19 March 2006 - 06:27 PM
Is there any situation in which you would want to remove a control from its parent without deleting the parent? If not, I suggest just using the destructor you posted above. It will recursively delete all children upon deletion of the top-level control. So there would be no need to call 'delete menuitem', as 'delete window' will delete all the controls in the correct order.
Otherwise, I suggest creating a new member function whose purpose is to remove a child from a control. You could tell this member not to do anything if it was called while destructing, e.g. by using a private flag.
Another approach might be to set the child pointer in the list to NULL when the child is deleted. But then whenever you looped over the children you would have to check to be sure you skipped over null pointers.
#12
Posted 19 March 2006 - 06:35 PM
Reedbeta said:
The idea was to make this library work like a GUI builder too, like when i #define DESIGN, i can drag&drop, modify, delete the widgets. It kind of worked, then i thought to switch to vc++2005 and it stopped working. Anyway, thank you all for your help, i will try again.
#13
Posted 19 March 2006 - 08:32 PM
#14
Posted 19 March 2006 - 10:57 PM
std::vector<WinObject *>::iterator it;
if(parent){
it=parent->children.begin();
while(it!=parent->children.end())
if(this==*it){
parent->children.erase(it);
break;
}
}
while(children.size()){
it=children.begin();
delete *it;
}
@Reedbeta:
i know you dont like it (though i cant see any obvious error), but all the children widgets get deleted, it works in both vc6 and vc2005, so i guess i leave it as it is right now, at least for the moment.
#15
Posted 20 March 2006 - 01:19 AM
That may work when you are deleting the parent, so it deletes all its children in order, but it won't work if you want to delete a single arbitrary child (like in your GUI-builder idea). You're not incrementing the iterator in the first loop, so it will only find 'this' in parent->children if 'this' is the first element!
#16
Posted 20 March 2006 - 12:00 PM
anyway, it looks that puting the "it=children.begin();" inside the while loop got the job done. dont ask me why.
#17
Posted 20 March 2006 - 01:38 PM
-
Currently working on: the 3D engine for Tomb Raider.
#18
Posted 20 March 2006 - 04:26 PM
kyuzo: maybe a book about stl would be useful... I suggest Effective STL.
#19
Posted 20 March 2006 - 04:33 PM
kyuzo said:
std::vector<WinObject *>::iterator it;
if(parent){
it=parent->children.begin();
while(it!=parent->children.end())
if(this==*it){
parent->children.erase(it);
break;
}
}
while(children.size()){
it=children.begin();
delete *it;
}
@Reedbeta:
i know you dont like it (though i cant see any obvious error), but all the children widgets get deleted, it works in both vc6 and vc2005, so i guess i leave it as it is right now, at least for the moment.
#20
Posted 20 March 2006 - 04:44 PM
1 user(s) are reading this topic
0 members, 1 guests, 0 anonymous users












