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

David Abrahams dave at boost-consulting.com
Sun Jul 6 00:35:28 CEST 2003

Prabhu Ramachandran <prabhu at aero.iitm.ernet.in> writes:

> Hi,
> I have a question that I'm not sure has much to do with Boost.Python
> itself but I'm wrapping some code via Boost.Python and need to know
> what the best approach is to solve the problem.
> The code is designed to be used by allocating objects on the heap (via
> new) and handing them off to very simple containers that manage these
> objects.  The lifetime of the objects is also managed by the
> container.  So here is a quick example.
> // --------------------
> class Obj {
> public:
>     Obj();
>     ~Obj();
> };
> class Mgr {
> public:
>     Mgr();
>     ~Mgr(); // deletes memory for objects in container.
>     void add(Obj* a);
>     void popBack();
> private:
>     std::vector<Obj*> arr;
> };
> void usage()
> {
>     Obj *o = new Obj();
>     Mgr *m = new Mgr();
>     m->add(o);
>     delete m;
> }
> // --------------------
> 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.  

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

> Anyway, I want to wrap the code above (except the usage function)
> and want to arrange for Boost.Python to allocate all of the objects,
> Obj and Mgr in the heap by default.  After wrapping the above via
> Boost.Python and using it from Python this is what happens:
>>>> 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++.  

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

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

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

> 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

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

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

    class_<Obj, std::auto_ptr<Obj> >("Obj")

does that.

> 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.  

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

    >>> del a

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

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

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

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

> Also, is the above approach of creating objects and handing them off
> to a manager a bad thing to do in general?  

By raw pointer?  Usually.

> Whats a better approach?

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

> This is a generic c++ question but the issue arises in the context
> of wrapping so I thought it sufficient relevant to post here and not
> a c++ list.  I'm sorry if this is inappropriate.
> Any suggestions will be much appreciated.

Dave Abrahams
Boost Consulting

More information about the Cplusplus-sig mailing list