[C++-sig] Re: Allocating objects on the heap by default.

Prabhu Ramachandran prabhu at aero.iitm.ernet.in
Sun Jul 6 05:04:59 CEST 2003


Hi David,

Thanks for the response!  Makes many things clear.

>>>>> "DA" == David Abrahams <dave at boost-consulting.com> writes:

    >> Perhaps the design is totally stupid, but its used consistently
    >> everywhere and quite simple once you know you can't delete an
    >> object you created and passed to a manager.  Juas as the user
    >> has to manage and remember to invoke delete for every new he
    >> has to remember that the manager manages memory as well.  I
    >> don't see that as a bad decision but I guess purists would not
    >> agree with me.

    DA> Nor pragmatists.  You should use std::vector<shared_ptr<Obj> >
    DA> and handle only shared_ptr<Obj> everywhere and then users
    DA> don't need to remember to delete anything, ever.

Hmm, so you are saying none of the functions should have ever been
written to deal with raw pointers at all and should all have used
shared_ptr?  But at some point using shared_ptr requires one to handle
reference cycles and figure how to break them (using weak_ptrs).  I'll
admit that this is probably rare (although I can think of a few
candidates in my code) and a lot easier to deal with.  It also
requires that the users generate shared_ptrs when they create a new
object.  Am I correct?  There are also performance issues I'll need to
worry about.  The boost "smart pointer" docs should prove useful here.
If this is what it takes perhaps I'll clean up my library to do this
correctly in the future.  For now I'll stick to the existing impure
and non-pragmatic approach. :)

    >>>>> import test a = test.Obj() b = test.Mgr() b.add(a) del b
    >> Segmentation fault.
    >>
    >> Trouble here is that Obj is not allocated on the heap but on
    >> the stack, just as one would expect in C++.

    DA> No, everything you construct from Python is allocated on the
    DA> heap.  The trouble here is that:

    DA> 1. the "a" object thinks it still has ownership of the Obj
    DA>      instance.

    DA> 2. The Obj instance is essentially allocated as a member of a
    DA>      "holder" object which is part of the Python object (on
    DA>      the heap) so you can't delete it.  You could only delete
    DA>      the outer object (if it were allocated with new, which it
    DA>      isn't).

Ahh, yes.  My analysis was poor.  Thanks for this.  Its now so much
clearer.

    >> Yes, I read the penultimate FAQ entry and my question is: can I
    >> arrange the wrappers to automatically allocate Obj and Mgr
    >> objects on the heap and additionally be handled by a shared_ptr

    DA> shared_ptr won't help you because you have no way to release
    DA> ownership and your Mgr class expects to be able to call delete
    DA> here.

Yes, so auto_ptr is my friend over here.

    >> /auto_ptr without having to write a factory function like
    >> NewObj for every single class?

    DA>     class_<Obj, std::auto_ptr<Obj> >("Obj")
    DA>         ...
    DA>         ;

    DA> does that.

Neat.  I missed out looking at class_'s HeldType.  This solves most of
my problems here.  Wonderful!

Now I need to get Pyste to do this also.  Currently Pyste registers a
::register_ptr_to_python< std::auto_ptr< Obj > >(); which from what I
gather won't allow auto_ptr to handle a newly constructed Obj
instance.  Is this correct?  So should Pyste's use_auto_ptr also pass
a HeldType as std::auto_ptr<Obj>?  Or should this be another option?

    >> I'd like to avoid writing factory functions just to do this
    >> since I have lots of classes like this.  If the object is
    >> allocated on the heap by default and I manage the object via
    >> boost::shared_ptr then the above segfault will not happen.

    DA> In that case, if you're lucky, you'll get a segfault later
    DA> when you write

    >>>> del a

Yes,  my mistake.

    >> Is there a way that this can be handled easily?  Alternatively
    >> can this be generated via Pyste/Python magic?

    DA> You need to write thin wrappers for functions such as Mgr::add
    DA> which take auto_ptr<Obj> instead of Obj* if you want to
    DA> transfer ownership in this way.  When we get luabind
    DA> integration you won't have to do that, though.

Well, I was considering adding auto_ptr support to the library itself
by overloading the add type of methods to accept an auto_ptr also.
This will fix the issue.

    >> FWIW and FYI, not that it matters but SWIG does this by default
    >> -- allocates everything via new and deals with the resulting
    >> opaque pointers.

    DA> by dealing with opaque pointers, SWIG leaves your Python at
    DA> the mercy of your C++, which is IMO a bad thing.

Yes, and this necessitates using the 'thisown' ownership flag in SWIG.
That does indeed allow the user to shoot himself in the foot and take
the interpreter along with him.

    >> Whats a better approach?

    DA> Use smart pointers in your manager's interface.  Note that
    DA> smart pointers are just lower level "managers".

Many thanks!  For now I'll add overloads to handle an auto_ptr<T> and
later consider moving to shared_ptr.  I still need to get a handle on
the performance of shared_ptr though.

The only issue that I need clarification is on how Pyste should do
handle this.  When use_auto_ptr(Obj) is specified should it register
both the to_python converter and also pass the HeldType as auto_ptr or
should the HeldType parameter be handled by something like
handle_with_auto_ptr(Obj)?  I think the latter is better but am not
quite sure.  I can submit a patch to handle this if this its OK.

Thanks again David, I think this clears up most matters for me.

regards,
prabhu




More information about the Cplusplus-sig mailing list