Storing a reference to an object ...
BlitzMax Forums/BlitzMax Programming/Storing a reference to an object ...
| ||
| I have a conceptual problem, and I can't figure out the most effective way to do it. I have two objects of the exact same type, but I want one to be the "parent" of the other, so that when I manipulate one object I can then call back and perform functions on the parent as well. In short, when I create the "child", I want the "parent" to become inactive (through a flag setting). When the child has finished doing what it is going to do, I want it to reactivate (through the same flag) the parent. I thought of creating parent/child lists, but iterating through lists to find a single object seemed inefficient. I also considered using pointers, but I'm not comfortable enough with how Blitz handles memory to be sure of the form. This is the kind of thing I wanted to do:
'-----------------------------------------------------------
'***********************Widget Type ************************
'-----------------------------------------------------------
Type Widget
Field Name$ = Null
Field Uses =0
Field pos_x,pos_y
Field Is_child = False
Field Parent:Widget Ptr = Null
Field Is_Active = True
Global WidgetList:TList
'*************************Create****************************
Function CreateWidget:Widget(temp_name$,x,y,num_uses)
temp_widget:widget = New widget
temp_widget.name = temp_name
temp_widget.pos_x = x
temp_widget.pos_y = y
temp_widget.uses = num_uses
If WidgetList=Null Then WidgetList = CreateList()
WidgetList.AddLast(temp_widget)
Return temp.widget
End Function
'***********************Make Widget a child of another **************
Method MakeChild (in:widget Ptr)
Is_child = True
parent = in
End Method
'********************** Where the Widget does stuff, and where it turns off the parent!!!!!
Method DoStuff()
Var Parent.MakeInactive() 'This is where I try to make the parent object inactive but
' it doesn't work. I need to know either how to make the
' pointer able to refernce the method of the object or a
' better way to do this!
...... Do other stuff .... 'All the rest of the programming.
Var Parent.MakeActive() ' Same issue...
End Method
' ********************* Sets Flag to active ************************
Method MakeActive ()
Is_active = True
End Method
'***********************Sets flag to inactive ********************
Method MakeInactive()
Is_active = False
End Method
End Type
'----------------------------------------------------------------
'******************** Starts the main program *******************
'----------------------------------------------------------------
Global thing1:widget = Widget.CreateWidget ("First",1,1,0)
Global thing2:widget = Widget.CreateWidget ("Second",1,1,0)
thing2.MakeChild(Varptr thing1)
thing2.DoStuff() '<----------------- The parent should be inactive While this is happening
Any suggestions are welcome. I'd really rather avoid pointers altogether, but I can't think of any other way that doesn't involve looking through a "ParentList" or ChildList" etc... |
| ||
| Why are you using pointers here in the first place? |
| ||
| Well, I couldn't create a widget field in a widget type to store the widget, etc... (good old recursive declarations). This shouldn't work:
Type widget
Field Parent:widget new widget
So I tried to find another way to store the location to the parent. Perhaps it would work without the "new widget", but I ended up going with a "ParentList:TList", because I realized one case where I might have to have more than one parent. I'm still curious if there is another (more efficient) way to store a parent, though. Besides, I could use some practice/experimentation with pointers and pointer references to variables, anyway... |
| ||
| Uh, you can have recursive handles. You just have to clean um up manually. |
| ||
an example of storing a parent on the child and cleaning up after yourself:
Strict
Framework BRL.Blitz
Import BRL.LinkedList
Type widget
Field name:String
Field parent:widget=Null
Field children:TList=Null
Function createWidget:widget(name:String,parent:widget=Null)
Local retval:widget=New widget
retval.name=name
retval.parent=parent
Return retval
EndFunction
Method addchild:widget(name:String)
' init the list
If children=Null Then children=New TList
Local retval:widget=widget.createWidget(name,Self)
children.AddLast(retval)
Return retval
EndMethod
Method clearChildren()
If children<>Null
Local child:widget
' make sure we clear our childrens children
For child=EachIn children
child.clearChildren()
Next
' clear out the list
children.Clear()
EndIf
EndMethod
' delete will never fire unless all other references are gone first
Method Delete()
DebugLog("destroying: "+name)
parent=Null
EndMethod
EndType
DebugLog("mem: "+MemAlloced())
' create the top level
Local testwidget:widget=widget.createWidget("top_level")
' create some first level children
testwidget.addchild(testwidget.name+": child1_1")
testwidget.addchild(testwidget.name+": child2_1")
testwidget.addchild(testwidget.name+": child3_1")
' create some second level children
Local child:widget
For child=EachIn testwidget.children
child.addchild(child.name+": child1_2")
child.addchild(child.name+": child2_2")
child.addchild(child.name+": child3_2")
Next
child=Null
DebugLog("13 total nodes we should see cleaned up at the End")
DebugLog("mem: "+MemAlloced())
' this is the big key... in order for something to be set to Null to work it
' must have no remaining references. this is a problem if a child still has
' a reference to the parent so you must get rid of the children first and those
' children must be sure to clean themselves up.
testwidget.clearchildren()
testwidget=Null
FlushMem
DebugLog("mem: "+MemAlloced())
should yield something like: mem: 1902 13 total nodes we should see cleaned up at the End mem: 3513 destroying: top_level: child3_1: child3_2 destroying: top_level: child3_1: child2_2 destroying: top_level: child3_1: child1_2 destroying: top_level: child2_1: child3_2 destroying: top_level: child2_1: child2_2 destroying: top_level: child2_1: child1_2 destroying: top_level: child1_1: child3_2 destroying: top_level: child1_1: child2_2 destroying: top_level: child1_1: child1_2 destroying: top_level: child3_1 destroying: top_level: child2_1 destroying: top_level: child1_1 destroying: top_level mem: 1902 Process complete |
| ||
| That's pretty much the way I ended up doing it, except I didn't store the parent in a reference at all, just created a list for them. Also, instead of storing children (as I won't be using the code that way.. though I did build in a search routine to sort through the list for any child that has a parent's name... just in case, but slower), I only stored the parent of the object. Didn't have a list.clear() on the destruction routine, though, so that will be added. My main curiousity was the difference in memory footprint across the different methods, as I may end up with lots of "widgets." But I guess if all that is being stored is a pointer to the object (whether is a object reference, a variable pointer, or an entry in a list), then it doesn't make much difference. Thanks for the input, folks! |