|
List Info
Thread: boost::python and custom smart pointer
|
|
| boost::python and custom smart pointer |
  Argentina |
2007-03-01 13:10:52 |
Hi,
I'd like to have my custom smart_ptr behave like
boost::shared_ptr
regarding from_python conversions. To_python converstions
work fine, but
the problem arises when I have an instance to a derived
class via a
smart_ptr to the base class MySmartPtr<Base> and this
has to be passed
to a function receiving MySmartPtr<Derived>. If I use
boost::shared_ptr
this works just fine. I think I'm doing something wrong in
MySmartPtr_from_python.
I'm pasting a simplified version of my code:
------ BEGIN C++ CODE ------
// Dummy smart pointer class.
template <typename T>
class MySmartPtr
{
public:
MySmartPtr() :
m_P(NULL)
{
}
MySmartPtr(T* a_P) :
m_P(a_P)
{
}
T* m_P;
};
namespace boost {
namespace python {
template <typename T>
T* get_pointer(MySmartPtr<T> const& a_P)
{
return a_P.m_P;
}
template <typename T>
struct pointee< MySmartPtr<T> >
{
typedef T type;
};
} // namespace python
} // namespace boost
template <class T>
struct MySmartPtr_from_python
{
static void* convertible(PyObject* p)
{
if (p == Py_None)
return p;
return
boost::python::converter::get_lvalue_from_python(p,
boost::python::converter::registered<
MySmartPtr<T> >::converters);
}
static void construct(PyObject* source,
boost::python::converter::rvalue_from_python_stage1_data*
data)
{
void* const storage =
((boost::python::converter::rvalue_from_python_storage<My
SmartPtr<T>
>*)data)->storage.bytes;
if (data->convertible == source) // This is because
convertible
returned p if p was Py_None.
new (storage) MySmartPtr<T>();
else
new (storage) MySmartPtr<T>(
*((MySmartPtr<T>*)data->convertible) );
data->convertible = storage;
}
};
class Base
{
public:
virtual ~Base()
{}
};
class Derived :
public Base
{
};
boost::shared_ptr<Base> build_ok()
{
return boost::shared_ptr<Base>(new Derived());
}
MySmartPtr<Base> build_fail()
{
return MySmartPtr<Base>(new Derived());
}
void test_ok(boost::shared_ptr<Derived> a_Derived)
{}
void test_fail(MySmartPtr<Derived> a_Derived)
{}
template <typename T>
void register_MySmartPtr_conversions()
{
boost::python::register_ptr_to_python<
MySmartPtr<Base> >();
boost::python::converter::registry::insert(
&MySmartPtr_from_python<T>::convertible,
&MySmartPtr_from_python<T>::construct,
boost::python::type_id< MySmartPtr<T> >()
);
}
BOOST_PYTHON_MODULE(bptest)
{
boost::python::class_<Base, boost::noncopyable>
class_Base("Base",
boost::python::no_init);
boost::python::register_ptr_to_python<
boost::shared_ptr<Base> >();
register_MySmartPtr_conversions<Base>();
boost::python::class_<Derived, boost::noncopyable,
boost::python::bases<Base> >
class_Derived("Derived",
boost::python::no_init);
boost::python::register_ptr_to_python<
boost::shared_ptr<Derived> >();
register_MySmartPtr_conversions<Derived>();
boost::python::def("build_ok", build_ok);
boost::python::def("test_ok", test_ok);
boost::python::def("build_fail", build_fail);
boost::python::def("test_fail", test_fail);
}
------ END C++ CODE ------
This python code fails to work:
import bptest
bptest.test_ok(bptest.build_ok())
bptest.test_fail(bptest.build_fail())
And this is the error that I get:
Boost.Python.ArgumentError: Python argument types in
bptest.test_fail(Derived)
did not match C++ signature:
test_fail(class MySmartPtr<class Derived>)
Thanks in advance.
--
Gabriel Becedillas
Developer
CORE SECURITY TECHNOLOGIES
_______________________________________________
C++-sig mailing list
C++-sig python.org
http:
//mail.python.org/mailman/listinfo/c++-sig
|
|
| Re: boost::python and custom smart
pointer |
  Argentina |
2007-03-01 14:03:31 |
Gabriel Becedillas wrote:
> Hi,
> I'd like to have my custom smart_ptr behave like
boost::shared_ptr
> regarding from_python conversions. To_python
converstions work fine, but
> the problem arises when I have an instance to a derived
class via a
> smart_ptr to the base class MySmartPtr<Base> and
this has to be passed
> to a function receiving MySmartPtr<Derived>. If I
use boost::shared_ptr
> this works just fine. I think I'm doing something wrong
in
> MySmartPtr_from_python.
> I'm pasting a simplified version of my code:
>
> ------ BEGIN C++ CODE ------
>
> // Dummy smart pointer class.
> template <typename T>
> class MySmartPtr
> {
> public:
> MySmartPtr() :
> m_P(NULL)
> {
> }
>
> MySmartPtr(T* a_P) :
> m_P(a_P)
> {
> }
>
> T* m_P;
> };
>
> namespace boost {
> namespace python {
>
> template <typename T>
> T* get_pointer(MySmartPtr<T> const& a_P)
> {
> return a_P.m_P;
> }
>
> template <typename T>
> struct pointee< MySmartPtr<T> >
> {
> typedef T type;
> };
>
> } // namespace python
> } // namespace boost
>
> template <class T>
> struct MySmartPtr_from_python
> {
> static void* convertible(PyObject* p)
> {
> if (p == Py_None)
> return p;
>
> return
boost::python::converter::get_lvalue_from_python(p,
> boost::python::converter::registered<
MySmartPtr<T>
> >::converters);
> }
>
> static void construct(PyObject* source,
>
boost::python::converter::rvalue_from_python_stage1_data*
data)
> {
> void* const storage =
>
((boost::python::converter::rvalue_from_python_storage<My
SmartPtr<T>
> >*)data)->storage.bytes;
>
> if (data->convertible == source) // This is
because convertible
> returned p if p was Py_None.
> new (storage) MySmartPtr<T>();
> else
> new (storage) MySmartPtr<T>(
> *((MySmartPtr<T>*)data->convertible) );
>
> data->convertible = storage;
> }
> };
>
> class Base
> {
> public:
> virtual ~Base()
> {}
> };
>
> class Derived :
> public Base
> {
> };
>
> boost::shared_ptr<Base> build_ok()
> {
> return boost::shared_ptr<Base>(new
Derived());
> }
>
> MySmartPtr<Base> build_fail()
> {
> return MySmartPtr<Base>(new Derived());
> }
>
> void test_ok(boost::shared_ptr<Derived>
a_Derived)
> {}
>
> void test_fail(MySmartPtr<Derived> a_Derived)
> {}
>
> template <typename T>
> void register_MySmartPtr_conversions()
> {
> boost::python::register_ptr_to_python<
MySmartPtr<Base> >();
>
> boost::python::converter::registry::insert(
>
&MySmartPtr_from_python<T>::convertible,
>
&MySmartPtr_from_python<T>::construct,
> boost::python::type_id< MySmartPtr<T>
>()
> );
> }
>
> BOOST_PYTHON_MODULE(bptest)
> {
> boost::python::class_<Base,
boost::noncopyable> class_Base("Base",
> boost::python::no_init);
> boost::python::register_ptr_to_python<
boost::shared_ptr<Base> >();
> register_MySmartPtr_conversions<Base>();
>
>
> boost::python::class_<Derived,
boost::noncopyable,
> boost::python::bases<Base> >
class_Derived("Derived",
> boost::python::no_init);
> boost::python::register_ptr_to_python<
boost::shared_ptr<Derived> >();
> register_MySmartPtr_conversions<Derived>();
>
> boost::python::def("build_ok",
build_ok);
> boost::python::def("test_ok", test_ok);
>
> boost::python::def("build_fail",
build_fail);
> boost::python::def("test_fail",
test_fail);
> }
>
> ------ END C++ CODE ------
>
> This python code fails to work:
>
> import bptest
>
> bptest.test_ok(bptest.build_ok())
> bptest.test_fail(bptest.build_fail())
>
> And this is the error that I get:
>
> Boost.Python.ArgumentError: Python argument types in
> bptest.test_fail(Derived)
> did not match C++ signature:
> test_fail(class MySmartPtr<class Derived>)
>
> Thanks in advance.
>
This function should be like this:
template <typename T>
void register_MySmartPtr_conversions()
{
boost::python::register_ptr_to_python<
MySmartPtr<T> >();
boost::python::converter::registry::insert(
&MySmartPtr_from_python<T>::convertible,
&MySmartPtr_from_python<T>::construct,
boost::python::type_id< MySmartPtr<T> >()
);
}
But its still failing.
--
Gabriel Becedillas
Developer
CORE SECURITY TECHNOLOGIES
_______________________________________________
C++-sig mailing list
C++-sig python.org
http:
//mail.python.org/mailman/listinfo/c++-sig
|
|
| Re: boost::python and custom smart
pointer |

|
2007-03-01 15:07:41 |
|
On 3/1/07, Gabriel Becedillas < gabriel.becedillas corest.com">gabriel.becedillas corest.com> wrote:
Gabriel Becedillas wrote: > Hi, > I'd like to have my custom smart_ptr behave like boost::shared_ptr > regarding from_python conversions. To_python converstions work fine, but > the problem arises when I have an instance to a derived class via a
> smart_ptr to the base class MySmartPtr<Base> and this has to be passed > to a function receiving MySmartPtr<Derived>. If I use boost::shared_ptr > this works just fine. I think I'm doing something wrong in
> MySmartPtr_from_python. > I'm pasting a simplified version of my code: For one of my project I also needed such functionality. I didn't find the answer. So I implemented pretty quick and simple work-around.
I had a factory class, which constructs objects and returns them using custom smart pointer. So, instead of exposing "create" function directly I created small wrapper and exposed it instead:
boost::python object create_wrapper( std::string name ){
custom_ptr<base_t> inst = create( name ); //call original function if( dynamic_cast< derived1_t*>( inst.get() ) ){ return boost::python::object( custom_ptr_dynamic_cast<derived1_t>( inst ) )
} else if( ... ){ ... }
}
This will give your users the behavior you want.
Now when I think about this, the better solution would be to introduce small call policy, which derives from the default_call_policies class
and contains the if-else+ casting logic.
If you use Py++, than it is pretty simple to apply the new call policy on all relevant functions.
-- Roman Yakovenko C++ Python language binding
http://www.language-binding.net/
|
| Re: boost::python and custom smart
pointer |
  Argentina |
2007-03-02 08:11:50 |
Gabriel Becedillas wrote:
> Hi,
> I'd like to have my custom smart_ptr behave like
boost::shared_ptr
> regarding from_python conversions. To_python
converstions work fine, but
> the problem arises when I have an instance to a derived
class via a
> smart_ptr to the base class MySmartPtr<Base> and
this has to be passed
> to a function receiving MySmartPtr<Derived>. If I
use boost::shared_ptr
> this works just fine. I think I'm doing something wrong
in
> MySmartPtr_from_python.
> I'm pasting a simplified version of my code:
>
> ------ BEGIN C++ CODE ------
>
> // Dummy smart pointer class.
> template <typename T>
> class MySmartPtr
> {
> public:
> MySmartPtr() :
> m_P(NULL)
> {
> }
>
> MySmartPtr(T* a_P) :
> m_P(a_P)
> {
> }
>
> T* m_P;
> };
>
> namespace boost {
> namespace python {
>
> template <typename T>
> T* get_pointer(MySmartPtr<T> const& a_P)
> {
> return a_P.m_P;
> }
>
> template <typename T>
> struct pointee< MySmartPtr<T> >
> {
> typedef T type;
> };
>
> } // namespace python
> } // namespace boost
>
> template <class T>
> struct MySmartPtr_from_python
> {
> static void* convertible(PyObject* p)
> {
> if (p == Py_None)
> return p;
>
> return
boost::python::converter::get_lvalue_from_python(p,
> boost::python::converter::registered<
MySmartPtr<T>
> >::converters);
> }
>
> static void construct(PyObject* source,
>
boost::python::converter::rvalue_from_python_stage1_data*
data)
> {
> void* const storage =
>
((boost::python::converter::rvalue_from_python_storage<My
SmartPtr<T>
> >*)data)->storage.bytes;
>
> if (data->convertible == source) // This is
because convertible
> returned p if p was Py_None.
> new (storage) MySmartPtr<T>();
> else
> new (storage) MySmartPtr<T>(
> *((MySmartPtr<T>*)data->convertible) );
>
> data->convertible = storage;
> }
> };
>
> class Base
> {
> public:
> virtual ~Base()
> {}
> };
>
> class Derived :
> public Base
> {
> };
>
> boost::shared_ptr<Base> build_ok()
> {
> return boost::shared_ptr<Base>(new
Derived());
> }
>
> MySmartPtr<Base> build_fail()
> {
> return MySmartPtr<Base>(new Derived());
> }
>
> void test_ok(boost::shared_ptr<Derived>
a_Derived)
> {}
>
> void test_fail(MySmartPtr<Derived> a_Derived)
> {}
>
> template <typename T>
> void register_MySmartPtr_conversions()
> {
> boost::python::register_ptr_to_python<
MySmartPtr<Base> >();
>
> boost::python::converter::registry::insert(
>
&MySmartPtr_from_python<T>::convertible,
>
&MySmartPtr_from_python<T>::construct,
> boost::python::type_id< MySmartPtr<T>
>()
> );
> }
>
> BOOST_PYTHON_MODULE(bptest)
> {
> boost::python::class_<Base,
boost::noncopyable> class_Base("Base",
> boost::python::no_init);
> boost::python::register_ptr_to_python<
boost::shared_ptr<Base> >();
> register_MySmartPtr_conversions<Base>();
>
>
> boost::python::class_<Derived,
boost::noncopyable,
> boost::python::bases<Base> >
class_Derived("Derived",
> boost::python::no_init);
> boost::python::register_ptr_to_python<
boost::shared_ptr<Derived> >();
> register_MySmartPtr_conversions<Derived>();
>
> boost::python::def("build_ok",
build_ok);
> boost::python::def("test_ok", test_ok);
>
> boost::python::def("build_fail",
build_fail);
> boost::python::def("test_fail",
test_fail);
> }
>
> ------ END C++ CODE ------
>
> This python code fails to work:
>
> import bptest
>
> bptest.test_ok(bptest.build_ok())
> bptest.test_fail(bptest.build_fail())
>
> And this is the error that I get:
>
> Boost.Python.ArgumentError: Python argument types in
> bptest.test_fail(Derived)
> did not match C++ signature:
> test_fail(class MySmartPtr<class Derived>)
>
> Thanks in advance.
>
I also forgot to say that upcasts aren't working either.
If I return a MySmartPtr<Base> and the concrete type
is Derived,
boost::python let me use the Derived interface (which is
great!), but
when this instance has to be passed back to C++ it'll only
match an
exact MySmartPtr<T> type. It won't do neither an
upcast nor a downcast.
After checking shared_ptr_from_python a litte bit I realize
that
convertible(...) is returning a raw T* to the object (when
the passed
PyObject is not Py_None) and that construct(...) is creating
a new
boost::shared_ptr from the raw T*.
converter::get_lvalue_from_python(p,
registered<T>::converters) is used
to extract the raw T* from the PyObject. This won't work for
me because
I need to extract the whole MySmartPtr<T>*, not just
the raw T*, in
order to copy the MySmartPtr<T> in construct(...).
Is there a way to do that ? Please keep in mind that I need
to check
both for upcasts and downcasts. My PyObject could hold a
MySmartPtr<Derived> instance and I'd like to pass it
to C++ as a
MySmartPtr<Base>, and the other way around (previously
checking if a
downcast is possible).
I really need to make MySmartPtr<T> to behave as
boost::shared_ptr<T>
regarding conversions.
Thanks a lot.
_______________________________________________
C++-sig mailing list
C++-sig python.org
http:
//mail.python.org/mailman/listinfo/c++-sig
|
|
| Re: boost::python and custom smart
pointer |

|
2007-03-02 12:25:22 |
On 3/2/07, Gabriel Becedillas <gabriel.becedillas corest.com> wrote:
>
> I also forgot to say that upcasts aren't working
either.
> If I return a MySmartPtr<Base> and the concrete
type is Derived,
> boost::python let me use the Derived interface (which
is great!), but
> when this instance has to be passed back to C++ it'll
only match an
> exact MySmartPtr<T> type. It won't do neither an
upcast nor a downcast.
Upcast is solvable, look documentation for
implicitly_convertible.
You also can take a look on complete example of exposing
custom smart
pointer here:
http://language-binding.n
et/pyplusplus/troubleshooting_guide/smart_ptrs/smart_ptrs.ht
ml
> After checking shared_ptr_from_python a litte bit I
realize that
> convertible(...) is returning a raw T* to the object
(when the passed
> PyObject is not Py_None) and that construct(...) is
creating a new
> boost::shared_ptr from the raw T*.
> converter::get_lvalue_from_python(p,
registered<T>::converters) is used
> to extract the raw T* from the PyObject. This won't
work for me because
> I need to extract the whole MySmartPtr<T>*, not
just the raw T*, in
> order to copy the MySmartPtr<T> in
construct(...).
>
> Is there a way to do that ? Please keep in mind that I
need to check
> both for upcasts and downcasts. My PyObject could hold
a
> MySmartPtr<Derived> instance and I'd like to pass
it to C++ as a
> MySmartPtr<Base>, and the other way around
(previously checking if a
> downcast is possible).
> I really need to make MySmartPtr<T> to behave as
boost::shared_ptr<T>
> regarding conversions.
There is only one person who can help you here: Dave
Abrahams.
--
Roman Yakovenko
C++ Python language binding
http://www.language-
binding.net/
_______________________________________________
C++-sig mailing list
C++-sig python.org
http:
//mail.python.org/mailman/listinfo/c++-sig
|
|
[1-5]
|
|