我正在为物理引擎编写Ruby扩展。此物理引擎具有链接到世界的主体,因此我的Ruby对象为World
和Body
。使用world->CreateBody
构造一个正文(使用C ++编写)并使用world->DestroyBody
进行销毁。
问题是Ruby GC在身体之前摧毁了世界。因此,当GC破坏物体时,世界不再存在,并且我得到分段错误。我知道我需要为GC标记某些内容(使用rb_gc_mark
),但我不知道在哪里。
World
类很标准,看起来像这样:
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;
}
Body
类略有不同,因为它需要从World对象创建(我不能简单地new
它)。所以它看起来像这样:
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;
}
所以我的问题是:
rb_gc_mark
标记,还是只在某些情况下才能这样做?哪些?rb_gc_mark
函数需要VALUE
。答案 0 :(得分:1)
您应该能够将VALUE
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()
需要VALUE *
。您应该能够编写一个简单的包装器(或使用std :: pair&lt;&gt;)来承载世界VALUE
。
警告:我还没有测试过任何上述代码,但它应该是方向正确的。