From: Lyle Johnson Date: 2001-07-27T00:05:08+09:00 Subject: [ruby-talk:18570] Re: yield in SWIG > %addmethods Foo { > void each () { > rb_yield(Wrap_Bar(cBar, self->BarPtr)); // return a valid Ruby > object > } > } > > The opinion that I am looking for is the use of the Wrap_Bar , which is > defined in SWIG. > The Wrap_Bar segment can be rewritten as the following (extracting what > Wrap_Bar defines): > > if (self->BarPtr) { > rb_yield(Data_Wrap_Struct(cBar, 0, 0, self->BarPtr)); > } > > So, what I want to know is if this is the best way to get rb_yield to > return a valid ruby object? Does > this do garbage collection correct, etc? Is there an easier way? ... I > must admit that I like this solution, > but I know that it is going to be used a lot, so I want to make sure > that it is the best solution. This looks fine, as long as you understand that because the third argument to Data_Wrap_Struct() is "0" (meaning you don't specify a free() function), Ruby's not going to try to free up the memory pointed to by self->BarPtr when it GC's the Ruby "Bar" instance associated with it. In this case, I don't think you want to do that anyways, so it should be OK. In contrast, here's an example where this could lead to a memory leak: VALUE each(VALUE self) { Bar *BarPtr = new Bar(); rb_yield(Data_Wrap_Struct(cBar, 0, 0, BarPtr)); return Qnil; } Now there's a problem: You allocated a new C++ Bar object on the heap but didn't tell Ruby's GC how to get rid of it. When Ruby's finished with the Ruby Bar instance, it will get GC'd OK but you leak this memory for the C++ object. To fix it you'd need a free() function, e.g. void free_Bar(void *BarPtr) { delete (Bar *) BarPtr; } VALUE each(VALUE self) { Bar *BarPtr = new Bar(); rb_yield(Data_Wrap_Struct(cBar, 0, free_Bar, BarPtr)); return Qnil; } Hope this helps, Lyle