175 lines
		
	
	
		
			6.2 KiB
		
	
	
	
		
			ReStructuredText
		
	
	
		
		
			
		
	
	
			175 lines
		
	
	
		
			6.2 KiB
		
	
	
	
		
			ReStructuredText
		
	
	
| 
								 | 
							
								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>> { // <-- 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.
							 |