| | 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 |
| |
|
| | .. code-block:: cpp |
| |
|
| | std::unique_ptr<Example> create_example() { return std::unique_ptr<Example>(new Example()); } |
| |
|
| | .. code-block:: cpp |
| |
|
| | 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. |
| |
|
| | .. code-block:: cpp |
| |
|
| | 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). |
| |
|
| | std::shared_ptr |
| | =============== |
| |
|
| | The binding generator for classes, :class:`class_`, can be passed a template |
| | type that denotes a special *holder* type that is used to manage references to |
| | the object. If no such holder type template argument is given, the default for |
| | a type named ``Type`` is ``std::unique_ptr<Type>``, which means that the object |
| | is deallocated when Python's reference count goes to zero. |
| |
|
| | It is possible to switch to other types of reference counting wrappers or smart |
| | pointers, which is useful in codebases that rely on them. For instance, the |
| | following snippet causes ``std::shared_ptr`` to be used instead. |
| |
|
| | .. code-block:: cpp |
| |
|
| | py::class_<Example, std::shared_ptr<Example> /* <- holder type */> obj(m, "Example"); |
| |
|
| | Note that any particular class can only be associated with a single holder type. |
| |
|
| | One potential stumbling block when using holder types is that they need to be |
| | applied consistently. Can you guess what's broken about the following binding |
| | code? |
| |
|
| | .. code-block:: cpp |
| |
|
| | class Child { }; |
| |
|
| | class Parent { |
| | public: |
| | Parent() : child(std::make_shared<Child>()) { } |
| | Child *get_child() { return child.get(); } /* Hint: ** DON'T DO THIS ** */ |
| | private: |
| | std::shared_ptr<Child> child; |
| | }; |
| |
|
| | PYBIND11_MODULE(example, m) { |
| | py::class_<Child, std::shared_ptr<Child>>(m, "Child"); |
| |
|
| | py::class_<Parent, std::shared_ptr<Parent>>(m, "Parent") |
| | .def(py::init<>()) |
| | .def("get_child", &Parent::get_child); |
| | } |
| |
|
| | The following Python code will cause undefined behavior (and likely a |
| | segmentation fault). |
| |
|
| | .. code-block:: python |
| |
|
| | from example import Parent |
| |
|
| | print(Parent().get_child()) |
| |
|
| | The problem is that ``Parent::get_child()`` returns a pointer to an instance of |
| | ``Child``, but the fact that this instance is already managed by |
| | ``std::shared_ptr<...>`` is lost when passing raw pointers. In this case, |
| | pybind11 will create a second independent ``std::shared_ptr<...>`` that also |
| | claims ownership of the pointer. In the end, the object will be freed **twice** |
| | since these shared pointers have no way of knowing about each other. |
| |
|
| | There are two ways to resolve this issue: |
| |
|
| | 1. For types that are managed by a smart pointer class, never use raw pointers |
| | in function arguments or return values. In other words: always consistently |
| | wrap pointers into their designated holder types (such as |
| | ``std::shared_ptr<...>``). In this case, the signature of ``get_child()`` |
| | should be modified as follows: |
| |
|
| | .. code-block:: cpp |
| |
|
| | std::shared_ptr<Child> get_child() { return child; } |
| |
|
| | 2. Adjust the definition of ``Child`` by specifying |
| | ``std::enable_shared_from_this<T>`` (see cppreference_ for details) as a |
| | base class. This adds a small bit of information to ``Child`` that allows |
| | pybind11 to realize that there is already an existing |
| | ``std::shared_ptr<...>`` and communicate with it. In this case, the |
| | declaration of ``Child`` should look as follows: |
| |
|
| | .. _cppreference: http://en.cppreference.com/w/cpp/memory/enable_shared_from_this |
| |
|
| | .. code-block:: cpp |
| |
|
| | class Child : public std::enable_shared_from_this<Child> { }; |
| |
|
| | .. _smart_pointers: |
| |
|
| | 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: |
| |
|
| | .. code-block:: cpp |
| |
|
| | PYBIND11_DECLARE_HOLDER_TYPE(T, SmartPtr<T>); |
| |
|
| | The first argument of :func:`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 |
| |
|
| | .. code-block:: cpp |
| |
|
| | 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 :ref:`macro_notes` 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: |
| |
|
| | .. code-block:: cpp |
| |
|
| | // 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>> { // < |
| | 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()``. |
| |
|
| | .. seealso:: |
| |
|
| | The file :file:`tests/test_smart_ptr.cpp` contains a complete example |
| | that demonstrates how to work with custom reference-counting holder types |
| | in more detail. |
| |
|