在Ruby和C ++之间交换数据

时间:2013-12-20 10:59:32

标签: c++ ruby embedded-ruby

我一直在阅读有关如何将Ruby嵌入到C ++程序中的教程。我已经找到了如何通过“rb_define_class”和“rb_define_class_under”定义一个类,以及通过“rb_define_method”定义一个类。现在我需要一个很好的例子来解释如何使用C ++编写的ruby类包装现有的C ++对象(指针)。例如:

    class MyClass
    {
    public:
        MyClass();
        void MyMethod();
    };

    VALUE myclass_init(VALUE self)
    {
        // I'd like to create a new MyClass instance and store its pointer inside "self"
    }

    VALUE myclass_meth(VALUE self)
    {
        // Now i need to retrieve the pointer to the object and call its method
    }

    int main(int argc, char* argv[])
    {
        ruby_init();
        ruby_init_loadpath();

        VALUE myclass = rb_define_class("MyWrapperClass", rb_cObject);
        rb_define_method(myclass, "initialize", (VALUE(*)(...))myclass_init, 0);
        rb_define_method(myclass, "myWrappedMethod", (VALUE(*)(...))myclass_meth, 0);

        // Loading ruby script skipped..

        ruby_finalize();

        return 0;
    }

我还需要一种方法来处理垃圾收集,以释放我的包装对象(以及做其他事情)。对不起英语不好,感谢任何试图回答这个问题的人!

1 个答案:

答案 0 :(得分:3)

要与Ruby的内存管理集成,您需要实现两个为您的一个对象分配和释放内存的函数 - 两者都不需要参数。 Ruby会将您的C ++数据结构“附加”到Ruby self VALUE,您需要使用几种方法来创建该附件,并从self获取C ++。

到目前为止,您的代码足够接近我刚刚填补了您的空白:

class MyClass
{
public:
    MyClass();
    void MyMethod();
};

//////////////////////////////////////////////////////////
// The next five are the functions that you were missing
// (although you could factor this differently if you chose)

MyClass *rb_create_myclass_obj() {
    return new MyClass();
}

void rb_delete_myclass_obj( MyClass *p_myclass ) {
    delete p_myclass;
    return;
}

VALUE myclass_as_ruby_class( MyClass *p_myclass , VALUE klass ) {
  return Data_Wrap_Struct( klass, 0, rb_delete_myclass_obj, p_myclass );
}

VALUE myclass_alloc(VALUE klass) {
  return myclass_as_ruby_class( rb_create_myclass_obj(), klass );
}

MyClass *get_myclass_obj( VALUE obj ) {
  MyClass *p_myclass;
  Data_Get_Struct( obj, MyClass, p_myclass );
  return p_myclass;
}

//////////////////////////////////////////////////////////

VALUE myclass_init(VALUE self)
{
    // You need do nothing here, Ruby will call myclass_alloc for 
    // you.
    return self;
}

VALUE myclass_meth(VALUE self)
{
    MyClass *p_myclass = get_myclass_obj( self );
    p_myclass->MyMethod();

    // If MyMethod returns some C++ structure, you will need to convert it
    // Here's how to return Ruby's nil

    return Qnil; 
}

int main(int argc, char* argv[])
{
    ruby_init();
    ruby_init_loadpath();

    VALUE myclass = rb_define_class("MyWrapperClass", rb_cObject);

    // The alloc function is how Ruby hooks up the memory management
    rb_define_alloc_func(myclass, myclass_alloc);

    rb_define_method(myclass, "initialize", (VALUE(*)(...))myclass_init, 0);
    rb_define_method(myclass, "myWrappedMethod", (VALUE(*)(...))myclass_meth, 0);

    // Loading ruby script skipped..

    ruby_finalize();

    return 0;
}