From: Tobias Peters Date: 2002-04-05T00:11:54+09:00 Subject: Re: Help: Ruby<->C++ callbacks On Thu, 4 Apr 2002, Luigi Ballabio wrote: > Hi all, > I'm writing a C++ extension to Ruby. I need to write a class which can > take a Ruby procedure and store it to be used as a callback, i.e., Be sure to understand ruby's memory management before attempting to design your classes. Since you want to write a "C++ extension to Ruby", you should defer all memory management to the ruby interpreter. You should start with an extension library that does practically nothing, just print out a few statements to cout when objects are created, freed, used, To get a feeling for how this is done. Suggestion for a base class that honors Ruby's memory management: // subclass this for real Ruby C++ extencion classes. class Rb_Base { // pointer back to ruby DATA object. Must not be used in // destructor! VALUE rb_value; // Garbage collection "mark" interface function static void mark(void * ptr) { reinterpret_cast(ptr)->mark_others(); } // Garbage collection "free" interface function static void free(void * ptr) { delete reinterpret_cast(ptr); } // disallow copying Rb_Base(const Rb_Base &); void operator=(const Rb_Base &); protected: // mark other known ruby objects here virtual void mark_others() {} // Extension object constructor, needs to know the ruby class of // this object Rb_Base(VALUE rb_class) { rb_value = Data_Wrap_Struct(rb_class, &Rb_Base::mark, &Rb_Base::free, this) } // destructor. Derived classes release C++ resources here. virtual ~Rb_Base() {} public: // convenience function for other C++ extension object that want // to mark this object virtual void mark_self() { rb_gc_mark(rb_value); } }; > > irb> c = Callback(proc { puts "Hello world!" }) > irb> c.doit > "Hello world!" > irb> > > This has not much use within the Ruby interpreter: however, it would allow > me to wrap Ruby code and use it as a callback in the C++ library I'm > interfacing. There is no need for this Callback class. The method of your extension class should take a block, store the VALUE pointer to it somewhere and call rb_gc_mark on it in its mark_others method. > Research on readme.ext and Programming Ruby yielded: > 1) rb_global_variable: it can protect a VALUE, but I don't know if the > process is undoable, i.e., if the VALUE can be marked again for gc. No need to do this. > 2) rb_gc_mark: it marks an object for gc, but can it be applied to one > previously protected by rb_global_variable? Also, if two callback objects > refer to a VALUE and one calls rb_gc_mark, will the latter be collected > regardless of the fact that another reference remains in use, or is some > kind of reference counting implemented? Sorry, but you misunderstood the purpose of the rb_gc_mark function. Yes, it marks an object on behalf of the garbage collector, but receiving a mark means that an object can still be accessed and will *not* be garbage collected. The garbage collector will collect only those objects that did not receive a mark. And you should only call rb_gc_mark during the mark phase of the garbage collector, that is, from within the mark function that you registered with Data_Wrap_Struct. Tobias