[C++-sig] boost::python and custom smart pointer

Gabriel Becedillas gabriel.becedillas at corest.com
Thu Mar 1 20:10:52 CET 2007


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




More information about the Cplusplus-sig mailing list