Skip to content

Commit c2144ab

Browse files
Support ownership transfer between C++ and Python with shared_ptr<T> and unique_ptr<T> for pure C++ instances and single-inheritance instances
1 parent 0da7ac7 commit c2144ab

18 files changed

+1676
-109
lines changed

docs/advanced/cast/overview.rst

+3
Original file line numberDiff line numberDiff line change
@@ -119,6 +119,9 @@ as arguments and return values, refer to the section on binding :ref:`classes`.
119119
| ``std::string_view``, | STL C++17 string views | :file:`pybind11/pybind11.h` |
120120
| ``std::u16string_view``, etc. | | |
121121
+------------------------------------+---------------------------+-------------------------------+
122+
| ``std::unique_ptr<T>``, | STL (or custom) smart | :file:`pybind11/cast.h` |
123+
| ``std::shared_ptr<T>``, etc. | pointers. | |
124+
+------------------------------------+---------------------------+-------------------------------+
122125
| ``std::pair<T1, T2>`` | Pair of two custom types | :file:`pybind11/pybind11.h` |
123126
+------------------------------------+---------------------------+-------------------------------+
124127
| ``std::tuple<...>`` | Arbitrary tuple of types | :file:`pybind11/pybind11.h` |

docs/advanced/classes.rst

+130-11
Original file line numberDiff line numberDiff line change
@@ -64,10 +64,10 @@ helper class that is defined as follows:
6464

6565
.. code-block:: cpp
6666
67-
class PyAnimal : public Animal {
67+
class PyAnimal : public py::wrapper<Animal> {
6868
public:
6969
/* Inherit the constructors */
70-
using Animal::Animal;
70+
using py::wrapper<Animal>::wrapper;
7171
7272
/* Trampoline (need one for each virtual function) */
7373
std::string go(int n_times) override {
@@ -89,6 +89,8 @@ function* slots, which defines the name of function in Python. This is required
8989
when the C++ and Python versions of the
9090
function have different names, e.g. ``operator()`` vs ``__call__``.
9191

92+
The base class ``py::wrapper<>`` is optional, but is recommended as it allows us to attach the lifetime of Python objects directly to C++ objects, explained in :ref:`virtual_inheritance_lifetime`.
93+
9294
The binding code also needs a few minor adaptations (highlighted):
9395

9496
.. code-block:: cpp
@@ -230,15 +232,15 @@ override the ``name()`` method):
230232

231233
.. code-block:: cpp
232234
233-
class PyAnimal : public Animal {
235+
class PyAnimal : public py::wrapper<Animal> {
234236
public:
235-
using Animal::Animal; // Inherit constructors
237+
using py::wrapper<Animal>::wrapper; // Inherit constructors
236238
std::string go(int n_times) override { PYBIND11_OVERLOAD_PURE(std::string, Animal, go, n_times); }
237239
std::string name() override { PYBIND11_OVERLOAD(std::string, Animal, name, ); }
238240
};
239-
class PyDog : public Dog {
241+
class PyDog : public py::wrapper<Dog> {
240242
public:
241-
using Dog::Dog; // Inherit constructors
243+
using py::wrapper<Dog>::wrapper; // Inherit constructors
242244
std::string go(int n_times) override { PYBIND11_OVERLOAD_PURE(std::string, Dog, go, n_times); }
243245
std::string name() override { PYBIND11_OVERLOAD(std::string, Dog, name, ); }
244246
std::string bark() override { PYBIND11_OVERLOAD(std::string, Dog, bark, ); }
@@ -258,24 +260,24 @@ declare or override any virtual methods itself:
258260
.. code-block:: cpp
259261
260262
class Husky : public Dog {};
261-
class PyHusky : public Husky {
263+
class PyHusky : public py::wrapper<Husky> {
262264
public:
263-
using Husky::Husky; // Inherit constructors
265+
using py::wrapper<Husky>::wrapper; // Inherit constructors
264266
std::string go(int n_times) override { PYBIND11_OVERLOAD_PURE(std::string, Husky, go, n_times); }
265267
std::string name() override { PYBIND11_OVERLOAD(std::string, Husky, name, ); }
266268
std::string bark() override { PYBIND11_OVERLOAD(std::string, Husky, bark, ); }
267269
};
268270
269271
There is, however, a technique that can be used to avoid this duplication
270272
(which can be especially helpful for a base class with several virtual
271-
methods). The technique involves using template trampoline classes, as
273+
methods). The technique (the Curiously Recurring Template Pattern) involves using template trampoline classes, as
272274
follows:
273275

274276
.. code-block:: cpp
275277
276-
template <class AnimalBase = Animal> class PyAnimal : public AnimalBase {
278+
template <class AnimalBase = Animal> class PyAnimal : public py::wrapper<AnimalBase> {
277279
public:
278-
using AnimalBase::AnimalBase; // Inherit constructors
280+
using py::wrapper<AnimalBase>::wrapper; // Inherit constructors
279281
std::string go(int n_times) override { PYBIND11_OVERLOAD_PURE(std::string, AnimalBase, go, n_times); }
280282
std::string name() override { PYBIND11_OVERLOAD(std::string, AnimalBase, name, ); }
281283
};
@@ -1080,3 +1082,120 @@ appropriate derived-class pointer (e.g. using
10801082
more complete example, including a demonstration of how to provide
10811083
automatic downcasting for an entire class hierarchy without
10821084
writing one get() function for each class.
1085+
1086+
.. _virtual_inheritance_lifetime:
1087+
1088+
Virtual Inheritance and Lifetime
1089+
================================
1090+
1091+
When an instance of a Python subclass of a ``pybind11``-bound C++ class is instantiated, there are effectively two "portions": the C++ portion of the base class's alias instance, and the Python portion (``__dict__``) of the derived class instance.
1092+
Generally, the lifetime of an instance of a Python subclass of a ``pybind11``-bound C++ class will not pose an issue as long as the instance is owned in Python - that is, you can call virtual methods from C++ or Python and have the correct behavior.
1093+
1094+
However, if this Python-constructed instance is passed to C++ such that there are no other Python references, then C++ must keep the Python portion of the instance alive until either (a) the C++ reference is destroyed via ``delete`` or (b) the object is passed back to Python. ``pybind11`` supports both cases, but **only** when (i) the class inherits from :class:`py::wrapper`, (ii) there is only single-inheritance in the bound C++ classes, and (iii) the holder type for the class is either :class:`std::shared_ptr` (suggested) or :class:`std::unique_ptr` (default).
1095+
1096+
.. seealso::
1097+
1098+
:ref:`holders` has more information regaring holders and how general ownership transfer should function.
1099+
1100+
When ``pybind11`` detects case (a), it will store a reference to the Python object in :class:`py::wrapper` using :class:`py::object`, such that if the instance is deleted by C++, then it will also release the Python object (via :func:`py::wrapper::~wrapper()`). The wrapper will have a unique reference to the Python object (as any other circumstance would trigger case (b)), so the Python object should be destroyed immediately upon the instance's destruction.
1101+
This will be a cyclic reference per Python's memory management, but this is not an issue as the memory is now managed via C++.
1102+
1103+
For :class:`std::shared_ptr`, this case is detected by placing a shim :func:`__del__` method on the Python subclass when ``pybind11`` detects an instance being created. This shim will check for case (a), and if it holds, will "resurrect" since it created a new reference using :class:`py::object`.
1104+
1105+
For :class:`std::unique_ptr`, this case is detected when calling `py::cast<unique_ptr<T>>`, which itself implies ownership transfer.
1106+
1107+
.. seealso::
1108+
1109+
See :ref:`unique_ptr_ownership` for information about how ownership can be transferred via a cast or argument involving ``unique_ptr<Type>``.
1110+
1111+
When ``pybind11`` detects case (b) (e.g. ``py::cast()`` is called to convert a C++ instance to `py::object`) and (a) has previously occurred, such that C++ manages the lifetime of the object, then :class:`py::wrapper` will release the Python reference to allow Python to manage the lifetime of the object.
1112+
1113+
.. note::
1114+
1115+
This mechanism will be generally robust against reference cycles in Python as this couples the two "portions"; however, it does **not** protect against reference cycles with :class:`std::shared_ptr`. You should take care and use :class:`std::weak_ref` or raw pointers (with care) when needed.
1116+
1117+
.. note::
1118+
1119+
There will a slight difference in destructor order if the complete instance is destroyed in C++ or in Python; however, this difference will only be a difference in ordering in when :func:`py::wrapper::~wrapper()` (and your alias destructor) is called in relation to :func:`__del__` for the subclass. For more information, see the documentation comments for :class:`py::wrapper`.
1120+
1121+
For this example, we will build upon the above code for ``Animal`` with alias ``PyAnimal``, and the Python subclass ``Cat``, but will introduce a situation where C++ may have sole ownership: a container. In this case, it will be ``Cage``, which can contain or release an animal.
1122+
1123+
.. note::
1124+
1125+
For lifetime, it is important to use a more Python-friendly holder, which in this case would be :class:`std::shared_ptr`, permitting an ease to share ownership.
1126+
1127+
.. code-block:: cpp
1128+
1129+
class Animal {
1130+
public:
1131+
virtual ~Animal() { }
1132+
virtual std::string go(int n_times) = 0;
1133+
};
1134+
1135+
class PyAnimal : public py::wrapper<Animal> {
1136+
public:
1137+
/* Inherit the constructors */
1138+
using py::wrapper<Animal>::wrapper;
1139+
std::string go(int n_times) override {
1140+
PYBIND11_OVERLOAD_PURE(std::string, Animal, go, n_times);
1141+
}
1142+
};
1143+
1144+
class Cage {
1145+
public:
1146+
void add(std::shared_ptr<Animal> animal) {
1147+
animal_ = animal;
1148+
}
1149+
std::shared_ptr<Animal> release() {
1150+
return std::move(animal_);
1151+
}
1152+
private:
1153+
std::shared_ptr<Animal> animal_;
1154+
};
1155+
1156+
And the following bindings:
1157+
1158+
.. code-block:: cpp
1159+
1160+
PYBIND11_MODULE(example, m) {
1161+
py::class_<Animal, PyAnimal, std::shared_ptr<Animal>> animal(m, "Animal");
1162+
animal
1163+
.def(py::init<>())
1164+
.def("go", &Animal::go);
1165+
1166+
py::class_<Cage, std::shared_ptr<Cage>> cage(m, "Cage")
1167+
.def(py::init<>())
1168+
.def("add", &Cage::add)
1169+
.def("release", &Cage::release);
1170+
}
1171+
1172+
With the following Python preface:
1173+
1174+
.. code-block:: pycon
1175+
1176+
>>> from examples import *
1177+
>>> class Cat(Animal):
1178+
... def go(self, n_times):
1179+
... return "meow! " * n_times
1180+
...
1181+
>>> cage = Cage()
1182+
1183+
Normally, if you keep the object alive in Python, then no additional instrumentation is necessary:
1184+
1185+
.. code-block:: pycon
1186+
1187+
>>> cat = Cat()
1188+
>>> c.add(cat) # This object lives in both Python and C++.
1189+
>>> c.release().go(2)
1190+
meow! meow!
1191+
1192+
However, if you pass an instance that Python later wishes to destroy, without :class:`py::wrapper`, we would get an error that ``go`` is not implented,
1193+
as the `Cat` portion would have been destroyed and no longer visible for the trampoline. With the wrapper, ``pybind11`` will intercept this event and keep the Python portion alive:
1194+
1195+
.. code-block:: pycon
1196+
1197+
>>> c.add(Cat())
1198+
>>> c.release().go(2)
1199+
meow! meow!
1200+
1201+
Note that both the C++ and Python portion of ``cat`` will be destroyed once ``cage`` is destroyed.

docs/advanced/smart_ptrs.rst

+123-19
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,17 @@
1-
Smart pointers
2-
##############
1+
.. _holders:
2+
3+
Smart pointers and holders
4+
##########################
5+
6+
Holders
7+
=======
8+
9+
The binding generator for classes, :class:`class_`, can be passed a template
10+
type that denotes a special *holder* type that is used to manage references to
11+
the object. If no such holder type template argument is given, the default for
12+
a type named ``Type`` is ``std::unique_ptr<Type>``, which means that the object
13+
is deallocated when Python's reference count goes to zero. It is possible to switch to other types of reference counting wrappers or smart
14+
pointers, which is useful in codebases that rely on them, such as ``std::shared_ptr<Type>``, or even a custom type.
315

416
std::unique_ptr
517
===============
@@ -15,31 +27,100 @@ instances wrapped in C++11 unique pointers, like so
1527
1628
m.def("create_example", &create_example);
1729
18-
In other words, there is nothing special that needs to be done. While returning
19-
unique pointers in this way is allowed, it is *illegal* to use them as function
20-
arguments. For instance, the following function signature cannot be processed
21-
by pybind11.
30+
In other words, there is nothing special that needs to be done.
31+
32+
.. _unique_ptr_ownership:
33+
34+
Transferring ownership
35+
----------------------
36+
37+
It is also possible to pass ``std::unique_ptr<Type>`` as a function
38+
argument, or use ``py::cast<unique_ptr<Type>>(std::move(obj))``. Note that this tells pybind11 to not manage the memory for this object, and delegate that to ``std::unique_ptr<Type>``.
39+
For instance, the following function signature can be processed by pybind11:
2240

2341
.. code-block:: cpp
2442
2543
void do_something_with_example(std::unique_ptr<Example> ex) { ... }
2644
27-
The above signature would imply that Python needs to give up ownership of an
28-
object that is passed to this function, which is generally not possible (for
29-
instance, the object might be referenced elsewhere).
45+
The above signature does imply that Python needs to give up ownership of an
46+
object that is passed to this function. There are two ways to do this:
47+
48+
1. Simply pass the object in. The reference count of the object can be greater than one (non-unique) when passing the object in. **However**, you *must* ensure that the object has only **one** reference when C++ (which owns the C++ object).
49+
50+
To expand on this, when transferring ownership for ``std::unique_ptr``, this means that Pybind11 no longer owns the reference, which means that if C++ lets the ``std::unique_ptr`` destruct but if there is a dangling reference in Python, then you will encounter undefined behavior.
51+
52+
Examples situations:
53+
54+
* The C++ function is terminal (i.e. will destroy the object once it completes). This is generally not an issue unless a Python portion of the object has a non-trivial ``__del__`` method.
55+
* The Python object is passed to a C++ container which only tracks ``std::unique_ptr<Type>``. If the container goes out of scope, the Python object reference will be invalid.
56+
57+
.. note::
58+
59+
For polymorphic types that inherit from :class:`py::wrapper`, ``pybind11`` *can* warn about these situations.
60+
You may enable this behavior with ``#define PYBIND11_WARN_DANGLING_UNIQUE_PYREF``. This will print a warning to ``std::err`` if this case is detected.
61+
62+
2. Pass a Python "move container" (a mutable object that can "release" the reference to the object). This can be a single-item list, or any Python class / instance that has the field ``_is_move_container = True`` and has a ``release()`` function.
63+
64+
.. note::
65+
66+
When using a move container, this expects that the provided object is a **unique** reference, or will throw an error otherwise. This is a little more verbose, but will make debugging *much* easier.
67+
68+
As an example in C++:
69+
70+
.. code-block:: cpp
71+
72+
void terminal_func(std::unique_ptr<Example> obj) {
73+
obj.do_something(); // `obj` will be destroyed when the function exits.
74+
}
75+
76+
// Binding
77+
py::class_<Example> example(m, "Example");
78+
m.def("terminal_func", &terminal_func);
79+
80+
In Python, say you would normally do this:
81+
82+
.. code-block:: pycon
83+
84+
>>> obj = Example()
85+
>>> terminal_func(obj)
86+
87+
As mentioned in the comment, you *must* ensure that `obj` is not used past this invocation, as the underlying data has been destroyed. To be more careful, you may "move" the object. The following will throw an error:
88+
89+
.. code-block:: pycon
90+
91+
>>> obj = Example()
92+
>>> terminal_func([obj])
93+
94+
However, this will work, using a "move" container:
95+
96+
.. code-block:: pycon
97+
98+
>>> obj = Example()
99+
>>> obj_move = [obj]
100+
>>> del obj
101+
>>> terminal_func(obj_move)
102+
>>> print(obj_move) # Reference will have been removed.
103+
[None]
104+
105+
or even:
106+
107+
.. code-block:: pycon
108+
109+
>>> terminal_func([Example()])
110+
111+
.. note::
112+
113+
``terminal_func(Example())`` also works, but still leaves a dangling reference, which is only a problem if it is polymorphic and has a non-trivial ``__del__`` method.
114+
115+
.. warning::
116+
117+
This reference counting mechanism is **not** robust aganist cyclic references. If you need some sort of cyclic reference, *please* consider using ``weakref.ref`` in Python.
30118

31119
std::shared_ptr
32120
===============
33121

34-
The binding generator for classes, :class:`class_`, can be passed a template
35-
type that denotes a special *holder* type that is used to manage references to
36-
the object. If no such holder type template argument is given, the default for
37-
a type named ``Type`` is ``std::unique_ptr<Type>``, which means that the object
38-
is deallocated when Python's reference count goes to zero.
39-
40-
It is possible to switch to other types of reference counting wrappers or smart
41-
pointers, which is useful in codebases that rely on them. For instance, the
42-
following snippet causes ``std::shared_ptr`` to be used instead.
122+
If you have an existing code base with ``std::shared_ptr``, or you wish to enable reference counting in C++ as well, then you may use this type as a holder.
123+
As an example, the following snippet causes ``std::shared_ptr`` to be used instead.
43124

44125
.. code-block:: cpp
45126
@@ -111,6 +192,12 @@ There are two ways to resolve this issue:
111192
112193
class Child : public std::enable_shared_from_this<Child> { };
113194
195+
.. seealso::
196+
197+
While ownership transfer is generally not an issue with ``std::shared_ptr<Type>``, it becomes an issue when an instance of a Python subclass of a pybind11 class is effectively managed by C++ (e.g. all live references to the object are from C++, and all reference in Python have "died").
198+
199+
See :ref:`virtual_inheritance_lifetime` for more information.
200+
114201
.. _smart_pointers:
115202

116203
Custom smart pointers
@@ -147,7 +234,7 @@ Please take a look at the :ref:`macro_notes` before using this feature.
147234

148235
By default, pybind11 assumes that your custom smart pointer has a standard
149236
interface, i.e. provides a ``.get()`` member function to access the underlying
150-
raw pointer. If this is not the case, pybind11's ``holder_helper`` must be
237+
raw pointer, and a ``.release()`` member function for move-only holders. If this is not the case, pybind11's ``holder_helper`` must be
151238
specialized:
152239

153240
.. code-block:: cpp
@@ -171,3 +258,20 @@ provides ``.get()`` functionality via ``.getPointer()``.
171258
The file :file:`tests/test_smart_ptr.cpp` contains a complete example
172259
that demonstrates how to work with custom reference-counting holder types
173260
in more detail.
261+
262+
.. warning::
263+
264+
Holder type conversion (see :ref:`smart_ptrs_casting`) and advanced ownership transfer (see :ref:`virtual_inheritance_lifetime`) is **not** supported for custom shared pointer types, due to constraints on dynamic type erasure.
265+
266+
.. _smart_ptrs_casting:
267+
268+
Casting smart pointers
269+
======================
270+
271+
As shown in the :ref:`conversion_table`, you may cast to any of the available holders (e.g. ``py::cast<std::shared_ptr<Type>>(obj)``) that can properly provide access to the underlying holder.
272+
273+
``pybind11`` will raise an error if there is an incompatible cast. You may of course cast to the exact same holder type. You may also move a ``std::unique_ptr<Type>`` into a ``std::shared_ptr<Type>``, as this is allowed. **However**, you may not convert a ``std::shared_ptr<Type>`` to a ``std::unique_ptr<Type>`` as you cannot release an object that is managed by ``std::shared_ptr<Type>``.
274+
275+
Additionally, conversion to ``std::unique_ptr<Type, Deleter>`` is not supported if ``Deleter`` is not ``std::default_deleter<Type>``.
276+
277+
Conversion to a different custom smart pointer is not supported.

include/pybind11/attr.h

+4-1
Original file line numberDiff line numberDiff line change
@@ -221,11 +221,14 @@ struct type_record {
221221
void *(*operator_new)(size_t) = ::operator new;
222222

223223
/// Function pointer to class_<..>::init_instance
224-
void (*init_instance)(instance *, const void *) = nullptr;
224+
void (*init_instance)(instance *, holder_erased) = nullptr;
225225

226226
/// Function pointer to class_<..>::dealloc
227227
void (*dealloc)(detail::value_and_holder &) = nullptr;
228228

229+
/// See `type_info::has_cpp_release`.
230+
instance::type_release_info_t release_info;
231+
229232
/// List of base classes of the newly created type
230233
list bases;
231234

0 commit comments

Comments
 (0)