Data_Wrap_Struct and Destruction Order

I am writing a Ruby extension for a physical engine. This physics engine has bodies that are connected to the world , which is why my objects are Ruby Worldand Body. The body is built (in C ++) with world->CreateBodyand destroyed with world->DestroyBody.

The problem is that Ruby GC destroys the world in front of bodies. So, when the GC destroys bodies, the world no longer exists, and I get a segmentation error. I know that I need to point out something for the GC (using rb_gc_mark), but I don't know where.


The class is Worldpretty standard, it looks like this:

extern "C" void world_free(void *w)
{
    static_cast<World*>(w)->~World();
    ruby_xfree(w);
}

extern "C" void world_mark(void *w)
{
    // ???
}

extern "C" VALUE world_alloc(VALUE klass)
{
    return Data_Wrap_Struct(klass, world_mark, world_free, ruby_xmalloc(sizeof(World)));
}

extern "C" VALUE world_initialize(VALUE self)
{
    World* w;
    Data_Get_Struct(self, World, w);
    new (w) World();
    return self;
}

The class is Bodyslightly different, since it must be created from a World object (I cannot just have newit). So it looks like this:

extern "C" void body_free(void* b)
{
    Body* body = static_cast<Body*>(b);
    World* world = body->GetWorld();
    world->DestroyBody(body);
}

extern "C" void body_mark(void* b)
{
    // ???
}

extern "C" VALUE body_alloc(VALUE klass)
{
    return Data_Wrap_Struct(klass, body_mark, body_free, 0);
}

extern "C" VALUE static_obj_initialize(VALUE self, VALUE world)
{
    Body* b;
    World* w;

    Data_Get_Struct(self, Body, b);
    Data_Get_Struct(world, World, w);

    b = w->CreateBody();
    DATA_PTR(self) = b;

    return self;
}

So my questions are:

  • GC?
  • ? rb_gc_mark, ? ?
  • ? , rb_gc_mark VALUE.
+4
1

VALUE of World , Body, .

, , - :

extern "C" VALUE static_obj_initialize(VALUE self, VALUE world)
{
    Body* b;
    World* w;

    Data_Get_Struct(self, Body, b);
    Data_Get_Struct(world, World, w);

    b = w->CreateBody();
    DATA_PTR(self) = b;
    rb_gc_register_address(&world);

    return self;
}

Body:

extern "C" void body_free(void* b)
{
    Body* body = static_cast<Body*>(b);
    World* world = body->GetWorld();
    world->DestroyBody(body);
    rb_gc_unregister_address(&world); //almost right
}

, rb_gc_unregister_address() a VALUE *. ( std:: pair < > ), World VALUE.

: , .

+1

All Articles