[C++-sig] Manage new object return policy (was Re: new to python; old to C++)

Paul Melis paul at pecm.nl
Wed Nov 12 19:22:24 CET 2008


David Abrahams wrote:
> on Mon Nov 10 2008, Paul Melis <paul-AT-pecm.nl> wrote:
>
>   
>> The FAQ entry on this doesn't really help, so perhaps I'm not using the return policy
>> correctly or missing something else. The full test code (which is actually quite
>> small) is attached.
>>     
>
> Please reduce it to its absolute minimum.  Remove every single thing you
> don't need in order to produce the result.  If the problem isn't
> glaringly obvious to you then, I will help.
>   
Well, I tried reducing in several different ways. The bottom line is
that I can't seem to produce this without using the wrapper class (or
perhaps I missed the right combination of return policies).

Simplest test case (see below for the rest of the files):

#!/usr/bin/env python
from boost import *
 
class MyCallback(Callback):
 
    def __init__(self):
        Callback.__init__(self)
 
    def __call__(self):
        return Value()
 
cb = MyCallback()
 
r = go(cb)


Storing a reference to the Value instance returned in __call__ keeps the
instance alive, so the dangling pointer is caused by the Value instance
that is returned getting destructed. But this only happens when the
instance is passed through go() as its return value. When calling cb
directly the Value is not destructed (as I would expect). What I don't
understand is why it is destructed when it *is* passed through go(),
shouldn't the manage_new_object policy keep it alive?

Regards,
Paul

// classes.h

#ifndef CLASSES_H
#define CLASSES_H

#include <stdlib.h>

class Value
{
public:
    Value()                 { printf("Value::Value()\n"); }
    Value(const Value& v)   { printf("Value::Value(const Value& v)\n"); }
    ~Value()                { printf("Value::~Value()\n"); }
};

class Callback
{
public:
    Callback()                      {}
    Callback(const Callback& cb)    {}
    virtual ~Callback()             {}
    // Returns new Value instance
    virtual Value* operator()() { return new Value(); }
};

Value *go(Callback *cb)
{
    return (*cb)();
};

#endif


// boost.cpp

// g++ -shared -fPIC -O3 -o boost.so -I/usr/include/python2.5 boost.cpp
-lboost_python -lpython2.5

#include <boost/python.hpp>
#include "classes.h"

namespace bp = boost::python;

struct CallbackWrap : Callback, bp::wrapper<Callback>
{
    virtual Value *operator()()
    {
        printf("CallbackWrap::operator()\n");

        if (bp::override call = this->get_override("__call__"))
        {
            printf("Have override for __call__, calling it\n");
            return call();
        }

        return Callback::operator()();
    }

    Value *default_call()
    {
        printf("CallbackWrap::default_call()\n");
        return this->Callback::operator()();
    }
};


BOOST_PYTHON_MODULE(boost)
{
    bp::class_< Value >("Value");

    bp::class_< CallbackWrap, boost::noncopyable >("Callback")
        .def("__call__", &Callback::operator(),
&CallbackWrap::default_call,
bp::return_value_policy<bp::manage_new_object>());

    bp::def("go", &go, bp::return_value_policy<bp::manage_new_object>());
}





More information about the Cplusplus-sig mailing list