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