Thanks, Matthias! It all seems to work now, and it clears up a few things. -Dave
On Apr 22, 7:02 am, Matthias Ernst <[email protected]> wrote: > On Thu, Apr 21, 2011 at 10:57 PM, Dave <[email protected]> wrote: > > I *think* understand your suggestion for keeping the parent/child > > cluster alive via an internal field, but let me make sure that I got > > it right: > > > Should I add a *second* internal field to the vector objects that > > points to info.This()? > > Yes, that's my suggestion. > > > When the parent (Sprite) callback is invoked, > > does it need to check if there's something in the second field, and if > > so, just skip deletion? > > No. You don't need to check anything. The magic is that the link from > child-wrapper to parent-wrapper is followed by the GC and > thus guarantees that the callback for the parent will not be invoked at all > as long as someone even only references the child. There is no need for a > child callback at all, everything gets managed through the parent. > > Small chart attached explains it all ;-) > > Matthias > > I'm guessing that the Vector callback would > > > > > > > > > then have to clear out its parents field so the parent could then > > delete properly when its callback is invoked again. > > > eg: > > > void DestroySprite( Persistent<Value> obj, > > void* param ) > > { > > // If this field is populated, then bail since we have an attached > > child. > > if (obj->GetPointerFromInternalField(1)) > > { > > return; > > } > > > CSprite* s = static_cast<CSprite*>(param); > > assert(s); > > > delete s; > > > obj.Dispose(); > > obj.Clear(); > > } > > > On Apr 19, 1:57 am, Matthias Ernst <[email protected]> wrote: > > > On Tue, Apr 19, 2011 at 12:31 AM, Dave <[email protected]> wrote: > > > > Hi all, > > > > > I'm experimenting with V8 for scripting in a game engine. However, I'm > > > > having trouble returning member objects of C++ classes by reference. > > > > For example, let's say I have the following C++ classes (trimmed for > > > > simplicity): > > > > > class Vector > > > > { > > > > public: > > > > int X; > > > > int Y; > > > > }; > > > > > class Sprite > > > > { > > > > public: > > > > Vector Position; > > > > }; > > > > > After wrapping these, I add a few Sprite objects to the global object > > > > (eg: Sprite_1, Sprite_2, etc.). In Javascript, I'd like to manipulate > > > > their positions, like so: > > > > > Sprite_1.Position.X = 32; > > > > > However, this doesn't work (ie: the sprite's position remains the > > > > same), but this does: > > > > > Sprite_1.Position = new Vector(32,0); // Sprite position is correctly > > > > updated > > > > > The reason the former doesn't work is because my 'GetPosition' > > > > accessor for the Sprite class will create a *new* Vector object and > > > > return that. In other words, the accessor will create a new (weak) > > > > persistent handle and wrap it around the external data. This > > > > essentially returns the vector as a value instead of a reference. I'd > > > > like to return it as a reference, since that would be the expected > > > > behavior. However, I'm not sure how I would go about doing that. > > > > > My code looks something like this: > > > > "Something like" is always difficult since I don't know what other > > details > > > to point out. > > > > > Handle<Value> GetPosition( Handle<String>, const AccessorInfo& info ) > > > > { > > > > Local<Object> obj = info.This(); > > > > Local<External> wrap = Local<External>::Cast( obj- > > > > >GetInternalField(0) ); > > > > "Set/GetPointerIn/FromInternalField" is simpler and might even be faster > > > than using External. > > > > > Vector pos = static_cast<Sprite*>( wrap->Value() )->Position(); > > > > Vector* v = new Vector(pos); > > > > > HandleScope handle_scope; > > > > Handle<Object> instance = VectorTemplate->InstanceTemplate()- > > > > >NewInstance(); // VectorTemplate is defined elsewhere > > > > Persistent<External> weak = > > > > Persistent<External>::New( External::New(v) ); > > > > I don't think this is what you want. You have now a weak reference from > > the > > > vector wrapper to the native vector. V8 GC may now any time collect the > > > native vector (no one else is referring to it) and leave your wrapper > > with > > > nothing. You want to create a weak reference to the wrapper object > > > "instance". > > > > > weak.MakeWeak( v, Vector_Dispose ); > > > > instance->SetInternalField(0,weak); > > > > > return handle_scope.Close(instance); > > > > } > > > > > I was thinking that instead of creating a new Vector, I could just > > > > wrap a local handle around the Sprite's Position member. > > > > This would be the right thing to do, wrapping &(sprite->Position). > > > > I'm guessing > > > > > that a persistent handle shouldn't be necessary since the lifetime of > > > > the member object is coupled with the parent Sprite. > > > > Yes and no. The member also only lives as long as the parent. The JS > > client > > > might acquire a reference to the child and then drop the reference to the > > > parent - which would allow the parent _and_ the child to be deleted on > > the > > > native side. Probably not what you want to happen. You need to make a > > > reference to the child keep the whole "cluster" alive. You'd do that by > > > introducing a reference from the child wrapper to the parent wrapper, > > e.g. > > > by adding an internal field to the child object in GetPosition that > > points > > > to info.This(). > > > > Matthias > > > > > Does anyone have any thoughts on this? I'm still getting used to V8's > > > > concepts... > > > > > Thanks, > > > > Dave > > > > > -- > > > > v8-users mailing list > > > > [email protected] > > > >http://groups.google.com/group/v8-users > > > -- > > v8-users mailing list > > [email protected] > >http://groups.google.com/group/v8-users > > heap.png > 44KViewDownload -- v8-users mailing list [email protected] http://groups.google.com/group/v8-users
