David Abrahams wrote:
> on Sat Nov 01 2008, Paul Melis <paul-AT-pecm.nl> wrote:
>
>   
>> Gustavo Carneiro wrote:
>>     
>>>     There's an interesting question about whether it's better to use
>>>     boost.python or SWIG. I've been using boost.python for years, so I
>>>     have a lot invested in it, but if I were starting from scratch, I
>>>     might consider using SWIG because it gives you the flexibility to
>>>     generate wrappers for languages other than Python.
>>>
>>>
>>> On the other hand, SWIG generates ugly and inneficient code, at least
>>> for the Python case.
>>>       
>> I'd like to see proof of the claim that SWIG's wrapper code is
>> inefficient. In my experience it is not more inefficient than what, for
>> example, boost.python via Py++ provides.
>>     
>
> I doubt that SWIG generates less efficient code.  However, I would be
> surprised if SWIG's is as careful about dealing with lifetime and
> ownership issues that are crucial to writing Pythonic and un-crashable
> bindings as Boost.Python is
In an attempt to compare SWIG and Boost on a simple synthetic benchmark I've 
become stuck on the following:

I have a method that returns a new instance of class Value and returns a 
pointer to it. The caller is then responsible for freeing of that instance at a 
suitable moment later on. I specify the manage_new_object return value policy 
for this method (and another one which basically returns its result) and this 
compiles fine. But when I run a small test script I get

CallbackWrap::operator()
Have override for __call__, calling it
Traceback (most recent call last):
  File "t_boost.py", line 25, in <module>
    r = obj.go(v1, v2)
ReferenceError: Attempt to return dangling pointer to object of type: Value

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.

Thanks in advance for any help,
Paul

#ifndef CLASSES_H
#define CLASSES_H

#include <stdlib.h>

class Value
{
public:
    Value()                 { _value = 0; }
    Value(int v)            { _value = v; }
    Value(const Value& v)   { _value = v._value; }
    int getValue() const    { return _value; }
    void setValue(int v)    { _value = v; }
protected:
    int     _value;
};

class Callback
{
public:
    Callback()                      {}
    Callback(const Callback& cb)    {}
    virtual ~Callback()             {}
    // Returns new Value instance
    virtual Value* operator()(const Value *v1, const Value *v2) { return new 
Value(v1->getValue() + v2->getValue()); }
};

class ObjectWithCallback
{
public:
    ObjectWithCallback()                                { _callback = NULL; }
    ObjectWithCallback(const ObjectWithCallback &obj)   { _callback = 
obj._callback; }

    void    setCallback(Callback *cb)   { _callback = cb; }

    // Returns new Value instance
    Value*  go(const Value *v1, const Value *v2)
    {
        if (_callback)
        {
            return (*_callback)(v1, v2);
            //printf("ObjectWithCallback::go() : value = %d\n", 
res->getValue());
        }
    }
protected:
    Callback    *_callback;
};

#endif
#!/usr/bin/env python
from boost import *

import time

class MyCallback(Callback):

    def __init__(self):
        Callback.__init__(self)

    def __call__(self, v1, v2):
        #print "MyCallback.__call__()"
        return Value(v1.getValue() * v2.getValue())

obj = ObjectWithCallback()
cb = MyCallback()
obj.setCallback(cb)

t0 = time.time()

for x in xrange(1000000):

    v1 = Value(123)
    v2 = Value(456)
    r = obj.go(v1, v2)

print "%.3f seconds" % (time.time() - t0)
// 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()(const Value *v1, const Value *v2)
    {
        printf("CallbackWrap::operator()\n");

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

        return Callback::operator()(v1, v2);
    }

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


BOOST_PYTHON_MODULE(boost)
{
    bp::class_< Value >("Value")
        .def(bp::init<int>())
        .def("getValue", &Value::getValue)
        .def("setValue", &Value::setValue);

    bp::class_< ObjectWithCallback >("ObjectWithCallback")
        .def("setCallback", &ObjectWithCallback::setCallback)
        .def("go", &ObjectWithCallback::go, 
bp::return_value_policy<bp::manage_new_object>());

    bp::class_< CallbackWrap, boost::noncopyable >("Callback")
        .def("__call__", &Callback::operator(), &CallbackWrap::default_call, 
bp::return_value_policy<bp::manage_new_object>());
}
_______________________________________________
Cplusplus-sig mailing list
Cplusplus-sig@python.org
http://mail.python.org/mailman/listinfo/cplusplus-sig

Reply via email to