Game Development Community

Whoa - SimGroup.clear() doesn't delete the children

by Orion Elenzil · in Torque Game Engine · 03/04/2007 (11:45 am) · 10 replies

SimGroup::clear() removes all the children of a SimGroup
and i'd always assumed it deleted them too, but apparently not.

Maybe i'm not thinking clearly.
Does that make sense ?

It certainly makes sense that you might not want to delete the children for SimSets, but SimGroups ?
(For those who don't know, a SimObject can belong to many SimSets, but only to one SimGroup)

here's an example with GuiControls which shows the problem,
using the console of the stock TGE 1.5 demo:
==>$a = new guiControl();
==>$b = new guiControl();
==>$a.add($b);
==>$a.clear();
==>echo(isObject($b));
1

.. the child control is now dangling. even if you don't assign it to a variable, it still dangles.


for dynamic GUIs which create and [clear] children on the fly and repeatedly,
this is potentially a bad memory leak.

proposal 1:
implement SimGroup::clear() s.t. it also deletes each child.

proposal 2:
implement something like the following:

ConsoleMethod(SimSet, deleteChildren, void, 2, 2, "deletes all children of this set")
{
   while (object->size() > 0)
      ((*object)[0])->deleteObject();
}


i would prefer to go w/ proposal 1,
but i worry that i'm missing some implication.

thoughts ?

#1
03/04/2007 (12:35 pm)
If you delete the SimGroup it should delete it's children, so instead of clearing it just delete it and recreate it :)
#2
03/04/2007 (12:41 pm)
I think this makes sense, and it is how cleanup groups work in script. You create a cleanup group and place objects in it, and then you delete it when you want to get rid of the objects that are within it.

But I also agree it is a bit confusing.
#3
03/04/2007 (12:48 pm)
Quote:If you delete the SimGroup it should delete it's children, so instead of clearing it just delete it and recreate it :)

uh.. not sure if you're joking or not.

that seems pretty unweildy for the case of dynamic GuiControls.

is there a reason *not* to go with proposal 1 ?
#4
03/04/2007 (12:53 pm)
Perhaps you placed some objects in the group you do not want to be deleted for that reason you clear it.

If this was made to clear = deletes you could not remove an object from a group at all. if the group is cleared or deleted, the object would be dead in ANY case.
#5
03/04/2007 (12:56 pm)
I guess i wish this had been implemented differently back in the dawn of the engine,
but i think you're right Marc - it's too risky to change the behaviour of clear() now.

going w/ proposal 2: deleteChildren().
#6
03/04/2007 (1:33 pm)
Considering you can delete the entire SimGroup and it deletes the contents it seems like a sufficient alternative to deleteChildren()... now I guess I can see the use of deleteChildren() though in the end deleting the simgroup and recreating it isn't a whole lot different and shouldn't cause any problems. Like Stefan has said that is how cleanup works... MissionCleanUp (if I got the name correct) is just a SimGroup that gets deleted when you end the mission. This is how this has been accomplished for a while... I see why you suggest what you do but it seems merely a different way to accomplish the same thing. That is the dual purpose of SimGroups... as you mentioned can only be in one SimGroup at a time and if you delete the SimGroup it deletes the objects.
#7
03/04/2007 (1:47 pm)
Hiya - thanks for writing back.

yes, i understand the mission cleanup mechanism.

i still feel that deleting the SimGroup and then recreating it just to delete all its children is more or less bad design however.

consider, once again, that all GuiControls are SimGroups.
perhaps i have a GuiControl which has a bunch of child controls which i want to dynamically re-create every now and then.

examples would be a list of inventory items or a tabbed-panel control.

i would very much like to write code like this:
function myContainerControl::repopulateInventory(%this, %items)
{
   // clear out what i have now
   %this.deleteChildren();
   
   // add in the new stuff
   for (%n = getFieldCount(%items) - 1; %n >=0 ; %n--)
   {
      %item = getField(%items, %n);
      %ctrl = new GuiButtonCtrl() {
         position = "0" SPC (%n * 20);
         extent   = "50 20";
         command  = "inspectItem(\"" @ %item @ "\");";
         text     = %item;
      };
      
      %this.add(%ctrl);
   }
}

.. requiring the deletion and recreation of the *container control* here would be extremely tedious -
maybe it's a GuiWindow control with all sorts of parameters. What size was it ? What position ? You'd have to store all those params and then re-create the control using them. That's just silly.
#8
03/04/2007 (1:54 pm)
Put another way,
in deleting and re-creating the containing SimGroup,
you're assuming that the SimGroup itself has no data; that's it's purely a featureless container.

which there's no need to create that limitation.
#9
03/05/2007 (10:30 am)
Well as far as GuiControls are concerned I can relate with that, then again looping through a SimGroup and calling delete on all it's objects is something easily done in script.

As far as a seperate SimGroup (minus the exception in which GuiControls derive from SimGroup, which in the end would be a different discussion since they are seperate object even if adding such functionality added to SimGroup would solve the problem and add a convenience to another):

Quote:which there's no need to create that limitation.

You may see it that way, while on the other hand I see no reason to limit it that way. When a SimGroup is deleted it deletes it's containing objects, knowing this I would simply create a script object and put it's ID in a SimGroup field and then store all the data in the ScriptObject (or inversley reference the SimGroup in the field of the ScriptObject). This way my data storing object is seperate than my object storing one, I could then delete the SimGroup whenever I want to delete all of the objects and simply re-create a fresh container.

I understand what you are saying and if you want that functionality then feel free to add it. I even think it would be something useful for us to add to the engine. I mean why not have a convenient function that acheives the same thing... though I don't see the issue you are talking about (again talking about SimGroup and not something derived from it). In the end it's easily done by deleting the group and if you can't do that (which again I don't see why you'd create that limitation, in the end that is one major use of a SimGroup) then simply loop through the objects and call delete from then... a simple script function.
#10
03/05/2007 (10:47 am)
Hey Matt - thanks for replying again.

Quote:
I would simply create a script object and put it's ID in a SimGroup field and then store all the data in the ScriptObject (or inversley reference the SimGroup in the field of the ScriptObject). This way my data storing object is seperate than my object storing one, I could then delete the SimGroup whenever I want to delete all of the objects and simply re-create a fresh container.
.. you go ahead and do that.
me, i'm going to call %container.deleteChildren() and be done with it.


edit: i should add that the SimGroups i'm most concerned about *are* GuiControls,
particularly inventory controls which contain hundreds and hundreds of children which i (now) delete and recreate as the user selects different subsets of clothing. since the numbers are large, i obviously want two things: 1) to have the logic around deleting these objects be water-tight, and something i'm not constantly worrying about later when things go wrong, and 2) performance. hence a C++ method which is simple, versatile, and fast.