C++ extension


#1

I am trying to understand some aspects of writing a ruby extension in
C++.

Actually what I am trying to do is wrap a C++ library and make it
accessible from ruby. Since I have been having problems with the library
that I am trying to wrap, I decided to create a really simple library
and try wrapping that.

The biggest problem that I am having is understanding scope. When I
create the wrapper for the class I create a new instance of the class
that I am wrapping and store it in a ptr. Then when I want to access
methods of this class the wrapper class just delegates to the ptr.
Simple stuff.

When I use a regular ptr things mostly work OK except that I can only
create one instance of the class.

The library I am trying to wrap uses smart pointers, so I created a
version of my code that uses simple pointers. The problem that I have
hear is that these objects then fall out of scope and the destructors
get called immediately after wrapper class method exists. The result of
course is that I get segmentation faults or weird results.

I have only a little experience in C++ and this is my first extension
that I have written.

How should I go about wrapping these c++ classes?

Thanks in advance.

Here is the code…
//extension.cpp
#include <ruby.h>
#include <test.h>
#include <smartptr.h>

typedef VALUE (ruby_method)(…);

auto_ptr test;
//test* test;

extern “C” VALUE t_TEST_init(VALUE self, VALUE value )
{
Param * param = new Param( NUM2INT( value ) );
test = auto_ptr( new Test( param ) );
//test = new Test( param );
return self;
}

extern “C” VALUE t_TEST_value(VALUE self)
{
return INT2NUM( test->ParamValue() );
}

auto_ptr param;
//Param* param;

extern “C” VALUE t_PARAM_init(VALUE self, VALUE value )
{
param = auto_ptr( new Param( 7 ) );
//param = new Param( NUM2INT( value ) );
return self;
}

extern “C” VALUE t_PARAM_value(VALUE self)
{
return INT2NUM( param->value() );
}

VALUE cTest;
VALUE cParam;

extern “C” void Init_Extension()
{
cTest = rb_define_class( “Test”, rb_cObject );
rb_define_method( cTest, “initialize”, (ruby_method*)
&t_TEST_init, 1 );
rb_define_method( cTest, “value”, (ruby_method*) &t_TEST_value,
0 );

    cParam = rb_define_class( "Param", rb_cObject );
    rb_define_method( cParam, "initialize", (ruby_method*) 

&t_PARAM_init, 1 );
rb_define_method( cParam, “value”, (ruby_method*)
&t_PARAM_value, 0 );
}

//test.h
#include <param.h>

class Test {

public:
Test(Param *);
~Test();
int ParamValue();
private:
Param *param;

};

//param.h
class Param {

public:
Param(int);
~Param();
int value();
private:
int internal;

};


#2

I’ve been a total wimp about accessing C/C++ libraries from Ruby. I
haven’t done anything particularly hard, but it’s always worked.

I use SWIG (www.swig.org). The most I’ve had to do is write a couple
helper functions and that’s about it. SWIG even comes with some
helpful Ruby examples, extconf.rb skeletons, and Makefile skeltons.
The SWIG documentation has a couple of sections on smart pointers.
While I was learning to use SWIG, their community was helpful with Ruby
specific suggestions.

Let us know how you do. Good Luck!


#3

How should I go about wrapping these c++ classes?

You need to wrap your class into a Ruby structure in order for this
to work right.

See: Data_Wrap_Struct and Data_Make_Struct for details

I’m not sure the implications of using an auto_ptr in the mix…as
I’ve never tried it. But, if you use the above methods you don’t
need it since Ruby will handle the lifetime of your object for you
(and provide a garbage collection hook for your destructor).