Smart pointers¶
std::unique_ptr¶
Given a class Example
with Python bindings, it’s possible to return
instances wrapped in C++11 unique pointers, like so
std::unique_ptr<Example> create_example() { return std::unique_ptr<Example>(new Example()); }
m.def("create_example", &create_example);
In other words, there is nothing special that needs to be done. While returning unique pointers in this way is allowed, it is illegal to use them as function arguments. For instance, the following function signature cannot be processed by pybind11.
void do_something_with_example(std::unique_ptr<Example> ex) { ... }
The above signature would imply that Python needs to give up ownership of an object that is passed to this function, which is generally not possible (for instance, the object might be referenced elsewhere).
Custom smart pointers¶
pybind11 supports std::unique_ptr
and std::shared_ptr
right out of the
box. For any other custom smart pointer, transparent conversions can be enabled
using a macro invocation similar to the following. It must be declared at the
top namespace level before any binding code:
PYBIND11_DECLARE_HOLDER_TYPE(T, SmartPtr<T>);
The first argument of PYBIND11_DECLARE_HOLDER_TYPE()
should be a
placeholder name that is used as a template parameter of the second argument.
Thus, feel free to use any identifier, but use it consistently on both sides;
also, don’t use the name of a type that already exists in your codebase.
The macro also accepts a third optional boolean parameter that is set to false by default. Specify
PYBIND11_DECLARE_HOLDER_TYPE(T, SmartPtr<T>, true);
if SmartPtr<T>
can always be initialized from a T*
pointer without the
risk of inconsistencies (such as multiple independent SmartPtr
instances
believing that they are the sole owner of the T*
pointer). A common
situation where true
should be passed is when the T
instances use
intrusive reference counting.
Please take a look at the General notes regarding convenience macros before using this feature.
By default, pybind11 assumes that your custom smart pointer has a standard
interface, i.e. provides a .get()
member function to access the underlying
raw pointer. If this is not the case, pybind11’s holder_helper
must be
specialized:
// Always needed for custom holder types
PYBIND11_DECLARE_HOLDER_TYPE(T, SmartPtr<T>);
// Only needed if the type's `.get()` goes by another name
namespace PYBIND11_NAMESPACE { namespace detail {
template <typename T>
struct holder_helper<SmartPtr<T>> { // <-- specialization
static const T *get(const SmartPtr<T> &p) { return p.getPointer(); }
};
}}
The above specialization informs pybind11 that the custom SmartPtr
class
provides .get()
functionality via .getPointer()
.
See also
The file tests/test_smart_ptr.cpp
contains a complete example
that demonstrates how to work with custom reference-counting holder types
in more detail.