Skip to content

Commit 2df39b2

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 ffcf754 commit 2df39b2

18 files changed

+1676
-111
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

+133-14
Original file line numberDiff line numberDiff line change
@@ -65,10 +65,10 @@ helper class that is defined as follows:
6565

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

93+
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`.
94+
9395
The binding code also needs a few minor adaptations (highlighted):
9496

9597
.. code-block:: cpp
@@ -157,7 +159,7 @@ Here is an example:
157159
158160
class Dachschund(Dog):
159161
def __init__(self, name):
160-
Dog.__init__(self) # Without this, undefind behavior may occur if the C++ portions are referenced.
162+
Dog.__init__(self) # Without this, undefined behavior may occur if the C++ portions are referenced.
161163
self.name = name
162164
def bark(self):
163165
return "yap!"
@@ -232,15 +234,15 @@ override the ``name()`` method):
232234

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

276278
.. code-block:: cpp
277279
278-
template <class AnimalBase = Animal> class PyAnimal : public AnimalBase {
280+
template <class AnimalBase = Animal> class PyAnimal : public py::wrapper<AnimalBase> {
279281
public:
280-
using AnimalBase::AnimalBase; // Inherit constructors
282+
using py::wrapper<AnimalBase>::wrapper; // Inherit constructors
281283
std::string go(int n_times) override { PYBIND11_OVERLOAD_PURE(std::string, AnimalBase, go, n_times); }
282284
std::string name() override { PYBIND11_OVERLOAD(std::string, AnimalBase, name, ); }
283285
};
@@ -997,5 +999,122 @@ described trampoline:
997999

9981000
MSVC 2015 has a compiler bug (fixed in version 2017) which
9991001
requires a more explicit function binding in the form of
1000-
``.def("foo", static_cast<int (A::*)() const>(&Publicist::foo));``
1001-
where ``int (A::*)() const`` is the type of ``A::foo``.
1002+
.. ``.def("foo", static_cast<int (A::*)() const>(&Publicist::foo));``
1003+
.. where ``int (A::*)() const`` is the type of ``A::foo``.
1004+
1005+
.. _virtual_inheritance_lifetime:
1006+
1007+
Virtual Inheritance and Lifetime
1008+
================================
1009+
1010+
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.
1011+
Generally, the lifetime of an instance of a Python subclass of a ``pybind11``-bound C++ class will note 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.
1012+
1013+
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).
1014+
1015+
.. seealso::
1016+
1017+
:ref:`holders` has more information regaring holders and how general ownership transfer should function.
1018+
1019+
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.
1020+
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++.
1021+
1022+
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`.
1023+
1024+
For :class:`std::unique_ptr`, this case is detected when calling `py::cast<unique_ptr<T>>`, which itself implies ownership transfer.
1025+
1026+
.. seealso::
1027+
1028+
See :ref:`unique_ptr_ownership` for information about how ownership can be transferred via a cast or argument involving ``unique_ptr<Type>``.
1029+
1030+
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.
1031+
1032+
.. note::
1033+
1034+
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.
1035+
1036+
.. note::
1037+
1038+
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`.
1039+
1040+
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.
1041+
1042+
.. note::
1043+
1044+
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.
1045+
1046+
.. code-block:: cpp
1047+
1048+
class Animal {
1049+
public:
1050+
virtual ~Animal() { }
1051+
virtual std::string go(int n_times) = 0;
1052+
};
1053+
1054+
class PyAnimal : public py::wrapper<Animal> {
1055+
public:
1056+
/* Inherit the constructors */
1057+
using py::wrapper<Animal>::wrapper;
1058+
std::string go(int n_times) override {
1059+
PYBIND11_OVERLOAD_PURE(std::string, Animal, go, n_times);
1060+
}
1061+
};
1062+
1063+
class Cage {
1064+
public:
1065+
void add(std::shared_ptr<Animal> animal) {
1066+
animal_ = animal;
1067+
}
1068+
std::shared_ptr<Animal> release() {
1069+
return std::move(animal_);
1070+
}
1071+
private:
1072+
std::shared_ptr<Animal> animal_;
1073+
};
1074+
1075+
And the following bindings:
1076+
1077+
.. code-block:: cpp
1078+
1079+
PYBIND11_MODULE(example, m) {
1080+
py::class_<Animal, PyAnimal, std::shared_ptr<Animal>> animal(m, "Animal");
1081+
animal
1082+
.def(py::init<>())
1083+
.def("go", &Animal::go);
1084+
1085+
py::class_<Cage, std::shared_ptr<Cage>> cage(m, "Cage")
1086+
.def(py::init<>())
1087+
.def("add", &Cage::add)
1088+
.def("release", &Cage::release);
1089+
}
1090+
1091+
With the following Python preface:
1092+
1093+
.. code-block:: pycon
1094+
1095+
>>> from examples import *
1096+
>>> class Cat(Animal):
1097+
... def go(self, n_times):
1098+
... return "meow! " * n_times
1099+
...
1100+
>>> cage = Cage()
1101+
1102+
Normally, if you keep the object alive in Python, then no additional instrumentation is necessary:
1103+
1104+
.. code-block:: pycon
1105+
1106+
>>> cat = Cat()
1107+
>>> c.add(cat) # This object lives in both Python and C++.
1108+
>>> c.release().go(2)
1109+
meow! meow!
1110+
1111+
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,
1112+
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:
1113+
1114+
.. code-block:: pycon
1115+
1116+
>>> c.add(Cat())
1117+
>>> c.release().go(2)
1118+
meow! meow!
1119+
1120+
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.

0 commit comments

Comments
 (0)