"add" function in swig and the ruby GC?

Hi,

I'm trying to write an add-function in C++ with swig, but I think that
ruby does not Garbage collect my objects. Example:

class Thingy {
    public:
        Thingy() { }
        ~Thingy() { cout << "Thingy is destructed."; }

        Thingy *add(const Thingy *other) const {
            Thingy *result = new Thingy();
            // ...
            return result;
        }
}

Using GC.start I can check that ruby does not destruct Thingies made
with "add". So, what is the correct way to do this? I could return a
Thingy instead of a Thingy*, but is this the preferred(TM) way?

best regards,
Richard

First of all, Ruby will never collect result in the case that an
exception is thrown. Better would be to write:

          Thingy *add(const Thingy *other) const {
              std::auto_ptr<Thingy> result(new Thingy);
              // ...
              return result.release();
          }

Secondly, because of Ruby's conservative GC, there is no guarantee that
the objects will ever be destroyed as long as your program is running.
If you need to be able to guarantee that a particular resource (e.g. a
socket or a lock) needs to be freed, you will be better off not relying
on the garbage collector but instead using a different mechanism, such
as blocks or an explicit method call to free the resource.

Now that we have that out of the way, you're probably still wondering
why your objects don't get cleaned up. Well, swig should clean up your
objects, but depending on how you've written your swig interface file
and/or your ruby script, that might not happen. Try to post the
smallest complete interface file and script that demonstrates the
problem, and then the answer may be more obvious.

Paul

···

On Mon, Oct 25, 2004 at 06:51:21AM +0900, Richard P. Groenewegen wrote:

class Thingy {
    public:
        Thingy() { }
        ~Thingy() { cout << "Thingy is destructed."; }

        Thingy *add(const Thingy *other) const {
            Thingy *result = new Thingy();
            // ...
            return result;
        }
}

Richard P. Groenewegen wrote:

Hi,

I'm trying to write an add-function in C++ with swig, but I think that
ruby does not Garbage collect my objects. Example:

class Thingy {
    public:
        Thingy() { }
        ~Thingy() { cout << "Thingy is destructed."; }

        Thingy *add(const Thingy *other) const {
            Thingy *result = new Thingy();
            // ...
            return result;
        }
}

Using GC.start I can check that ruby does not destruct Thingies made
with "add". So, what is the correct way to do this? I could return a
Thingy instead of a Thingy*, but is this the preferred(TM) way?

How could SWIG or Ruby possibly know that the pointer returned by your add method points to a newly created object on the heap. Swig does not interpret C++ Code, only types and signatures.

The solution to your problem is in the fine SWIG manual. Hint: %newobject

Tobias

Try to post the smallest complete interface file and script that
demonstrates the problem, and then the answer may be more obvious.

Thanks for the reply and the comment about auto_ptr. I'll be using
that. As for the smallest complete example:

//-------------------------------------------------------------------
// thingy.h
//-------------------------------------------------------------------
    #include <iostream>
    using namespace std;
    class Thingy {
        public:
            Thingy() {
                _number = ++number;
                cout << "Thingy " << _number << " constructed.\n";
            }
            ~Thingy() {
                cout << "Thingy " << _number << " destructed.\n";
            }
            Thingy * add(Thingy *other) {
                return new Thingy();
            }
            static int number;
        protected:
            int _number;
    };

//-------------------------------------------------------------------
// thingy.cxx
//-------------------------------------------------------------------
    #include "thingy.h"
    int Thingy::number = 0;

//-------------------------------------------------------------------
// thingy.i
//-------------------------------------------------------------------
    %module thingy

    %{
    #include "thingy.h"
    %}

    %include "thingy.h"

//-------------------------------------------------------------------
// irb output (slightly trimmed):
//-------------------------------------------------------------------
    > require 'thingy.so'
    > a = Thingy::Thingy.new
    Thingy 1 constructed.

    > b = Thingy::Thingy.new
    Thingy 2 constructed.

    > c = a.add(b)
    Thingy 3 constructed.

    irb(main):005:0> a,b,c, = 0,0,0

    irb(main):006:0> GC.start
    Thingy 2 destructed.
    Thingy 1 destructed.
    
As you can see. Thingy 3 does not get destructed. I tried changing
the function add to

    void add(Thingy *other, Thingy *OUTPUT) {
        OUTPUT = new Thingy();
    }

and include "typemaps.i" in the thingy.i file as (sort of) is
suggested in the swig documentation but that does not work.

best regards,
Richard

There is some interessting reading about this quind of problem in the SWIG
manual page 398 chapter 27.8.5.

···

On Tue, 26 Oct 2004, Tobias Peters wrote:

Richard P. Groenewegen wrote:
> Hi,
>
> I'm trying to write an add-function in C++ with swig, but I think that
> ruby does not Garbage collect my objects. Example:
>
> class Thingy {
> public:
> Thingy() { }
> ~Thingy() { cout << "Thingy is destructed."; }
>
> Thingy *add(const Thingy *other) const {
> Thingy *result = new Thingy();
> // ...
> return result;
> }
> }
>
> Using GC.start I can check that ruby does not destruct Thingies made
> with "add". So, what is the correct way to do this? I could return a
> Thingy instead of a Thingy*, but is this the preferred(TM) way?

How could SWIG or Ruby possibly know that the pointer returned by your
add method points to a newly created object on the heap. Swig does not
interpret C++ Code, only types and signatures.

The solution to your problem is in the fine SWIG manual. Hint: %newobject

Tobias