У меня есть расширение C, в котором у меня есть основной класс (класс А, например), созданные с классическим:рубиновые с расширения, как управлять сборкой мусора между 2 объектами
Data_Wrap_Struct
rb_define_alloc_func
rb_define_private_method(mymodule, "initialize" ...)
В этом одном классе есть экземпляр метод, который генерирует объект B. Эти объекты B могут генерироваться только из объектов A и иметь C-данные, которые зависят от данных, завернутых в экземпляр A.
I Объект A собран сборщиком мусора перед объектом B, это может привести к ошибке Seg.
Как я могу сказать GC не собирать экземпляр A, пока некоторые из его объектов B все еще остаются. Думаю, мне нужно использовать rb_gc_mark или что-то в этом роде. Должен ли я отмечать экземпляр A каждый раз, когда создается объект B?
Edit: Больше специфика Информация
Я пытаюсь написать расширение Clang. С clang вы сначала создаете CXIndex, из которого вы можете получить CXTranslationUnit, из которого вы можете получить CXDiagnostic и/или CXCursor и т. Д. вот простой пример:
Clangc::Index#new => Clangc::Index
Clangc::Index#create_translation_unit => Clangc::TranslationUnit
Clangc::TranslationUnit#diagnostic(index) => Clangc::Diagnostic
Вы можете увидеть код здесь: https://github.com/cedlemo/ruby-clangc
Edit 2: Раствор
материал для создания «B» объекты с ссылкой на «а» объект:
typedef struct B_t {
void * data;
VALUE instance_of_a;
} B_t;
static void
c_b_struct_free(B_t *s)
{
if(s)
{
if(s->data)
a_function_to_free_the_data(s->data);
ruby_xfree(s);
}
}
static void
c_b_mark(void *s)
{
B_t *b =(B_t *)s;
rb_gc_mark(b->an_instance_of_a);
}
VALUE
c_b_struct_alloc(VALUE klass)
{
B_t * ptr;
ptr = (B_t *) ruby_xmalloc(sizeof(B_t));
ptr->data = NULL;
ptr->an_instance_of_a = Qnil;
return Data_Wrap_Struct(klass, c_b_mark, c_b_struct_free, (void *) ptr);
}
функция с, которая используется для создания «B» объект из «а» объекта:
VALUE c_A_get_b_object(VALUE self, VALUE arg)
{
VALUE mModule = rb_const_get(rb_cObject, rb_intern("MainModule"));\
VALUE cKlass = rb_const_get(mModule, rb_intern("B"));
VALUE b_instance = rb_class_new_instance(0, NULL, cKlass);
B_t *b;
Data_Get_Struct(b_instance, B_t, b);
/*
transform ruby value arg to C value c_arg
*/
b->data = function_to_fill_the_data(c_arg);
b->instance_of_a = self;
return b_instance;
}
В Init_mainModule функции:
void Init_mainModule(void)
{
VALUE mModule = rb_define_module("MainModule");
/*some code ....*/
VALUE cKlass = rb_define_class_under(mModule, "B", rb_cObject);
rb_define_alloc_func(cKlass, c_b_struct_alloc);
}
же использование в rb_gc_mark можно найти в mysql2/внутр/mysql2/client.c (rb_mysql_client_mark function
) в проекте https://github.com/brianmario/mysql2
Когда вы говорите «сгенерируете», вы имеете в виду, что объекты 'B' выглядят автономными с Ruby, но связаны между собой? Будет ли ваша объектная модель иметь смысл, если вы можете сделать 'a_object.all_the_b_objects' и/или' b_object.parent_a_object'. , , с этими отношениями в игре ответ может быть несколько иным, если бы они не были. –
Объект B не может существовать без объекта A. Обтекаемые данные в объекте B зависят от обернутых данных в объекте A. Я хотел задать очень глобальный вопрос, но я добавил редактирование, чтобы проиллюстрировать этот вопрос тем, что я сейчас пытаюсь сделать. – cedlemo