List Info

Thread: boost::python and custom smart pointer




boost::python and custom smart pointer
country flaguser name
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++-sigpython.org
http:
//mail.python.org/mailman/listinfo/c++-sig

Re: boost::python and custom smart pointer
country flaguser name
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++-sigpython.org
http:
//mail.python.org/mailman/listinfo/c++-sig

Re: boost::python and custom smart pointer
user name
2007-03-01 15:07:41
On 3/1/07, Gabriel Becedillas < gabriel.becedillascorest.com">gabriel.becedillascorest.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 ){

&nbsp; &nbsp; custom_ptr<base_t&gt; inst = create( name ); //call original function
&nbsp;   if( dynamic_cast< derived1_t*>( inst.get() ) ){
 &nbsp;   ; &nbsp; return boost::python::object( custom_ptr_dynamic_cast<derived1_t>( inst ) )
   ; }
 &nbsp;  else if( ... ){
 &nbsp;   ; &nbsp; ...
   ; }

}

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
country flaguser name
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++-sigpython.org
http:
//mail.python.org/mailman/listinfo/c++-sig

Re: boost::python and custom smart pointer
user name
2007-03-02 12:25:22
On 3/2/07, Gabriel Becedillas <gabriel.becedillascorest.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++-sigpython.org
http:
//mail.python.org/mailman/listinfo/c++-sig

[1-5]

about | contact  Other archives ( Real Estate discussion Medical topics )