I am fairly new to boost.python and trying to expose the return value of a function to python.
The function signature looks like this:
std::unique_ptr<Message> someFunc(const std::string &str) const;
When calling the function in python, I get the following error:
TypeError: No to_python (by-value) converter found for C++ type: std::unique_ptr<Message, std::default_delete<Message> >
My function call in python looks like this:
a = mymodule.MyClass()
a.someFunc("some string here") # error here
I tried to expose the std::unique_ptr but just cant get it to work.. Does someone know how to properly expose the pointer class? Thanks!
Edit: I tried the following:
class_<std::unique_ptr<Message, std::default_delete<Message>>, bost::noncopyable ("Message", init<>())
;
This example compiles, but I still get the error mentioned above.
Also, I tried to expose the class Message
itself
class_<Message>("Message", init<unsigned>())
.def(init<unsigned, unsigned>())
.def("f", &Message::f)
;
My suggestion is to get the raw pointer from the
std::unique_ptr
container withget()
. You will have to careful to keep theunique_ptr
in scope for for whole time that you wish to use the raw pointer value, otherwise the object will be deleted and you'll have a pointer to an invalid area of memory.Boost supports
movable semantics
andunique_ptr
since v.1.55. But in my project I used previous version and made such simple wrapper:to create
unique_ptr<HierarchyT>
as Pythonshierarchy
and pass it to the function that accepts it by reference.Python code:
where C++ function is
float clusterize(unique_ptr<HierarchyT>& hier,...)
.Then to access results in Python make a call
hier()
to get the wrapped object from the unique_ptr:In short, Boost.Python does not support move-semantics, and therefore does not support
std::unique_ptr
. Boost.Python's news/change log has no indication that it has been updated for C++11 move-semantics. Additionally, this feature request forunique_ptr
support has not been touched for over a year.Nevertheless, Boost.Python supports transferring exclusive ownership of an object to and from Python via
std::auto_ptr
. Asunique_ptr
is essentially a safer version ofauto_ptr
, it should be fairly straight forward to adapt an API usingunique_ptr
to an API that usesauto_ptr
:boost::python::return_value_policy
with aboost::python::manage_new_object
result converter.unique_ptr
release control viarelease()
and return a raw pointerauto_ptr
. The FAQ mentions that pointers returned from C++ with amanage_new_object
policy will be managed viastd::auto_ptr
.auto_ptr
release control to aunique_ptr
viarelease()
Given an API/library that cannot be changed:
The
SpamFactory::make()
andSpamFactory::consume()
need to be wrapped via auxiliary functions.Functions transferring ownership from C++ to Python can be generically wrapped by a function that will create Python function objects:
The lambda delegates to the original function, and
releases()
ownership of the instance to Python, and the call policy indicates that Python will take ownership of the value returned from the lambda. Thempl::vector
describes the call signature to Boost.Python, allowing it to properly manage function dispatching between the languages.The result of
adapt_unique
is exposed asSpamFactory.make()
:Generically adapting
SpamFactory::consume()
is a more difficult, but it is easy enough to write a simple auxiliary function:The auxiliary function delegates to the original function, and converts the
auto_ptr
provided by Boost.Python to theunique_ptr
required by the API. TheSpamFactory_consume
auxiliary function is exposed asSpamFactory.consume()
:Here is a complete code example:
Interactive Python:
I think nowadays there is no way to do what you are looking for... The reason is because
std::unique_ptr<Message> someFunc(const std::string &str)
is returning by value, which means one of two things:Is someFunc() creating the object? In case YES, I think the solution is to create a wrapper, in case NO, you can return by reference:
expose the class:
and also the functions: