aboutsummaryrefslogtreecommitdiffstats
path: root/3rdparty/pybind11/docs/advanced/smart_ptrs.rst
diff options
context:
space:
mode:
Diffstat (limited to '3rdparty/pybind11/docs/advanced/smart_ptrs.rst')
-rw-r--r--3rdparty/pybind11/docs/advanced/smart_ptrs.rst173
1 files changed, 173 insertions, 0 deletions
diff --git a/3rdparty/pybind11/docs/advanced/smart_ptrs.rst b/3rdparty/pybind11/docs/advanced/smart_ptrs.rst
new file mode 100644
index 00000000..da57748c
--- /dev/null
+++ b/3rdparty/pybind11/docs/advanced/smart_ptrs.rst
@@ -0,0 +1,173 @@
+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 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()``.
+
+.. 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.