我正在为物理引擎编写一个 Ruby 扩展。此物理引擎具有链接到世界 的body,因此我的Ruby 对象是World
和Body
。主体是使用 world->CreateBody
构建(在 C++ 中)并使用 world->DestroyBody
销毁。
问题在于 Ruby GC 会先于 body 破坏世界。所以,当 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;
}
所以我的问题是:
- 我应该在 GC 上标记这两个对象中的哪一个?
- 我该怎么做?我是简单地用
rb_gc_mark
做标记,还是应该只在某些条件下做标记?哪些? - 我应该标记什么?标记函数仅接收指向我的结构的裸指针,但
rb_gc_mark
函数需要一个VALUE
。
最佳答案
您应该能够注册 VALUE
的 World
as busy 与 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<>)来承载世界 VALUE
.
警告:我没有测试过以上任何代码,但它的方向应该是正确的。
关于ruby - Data_Wrap_Struct 和销毁顺序,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/24932263/