Skip to content

Commit 76f4da3

Browse files
committed
[ci skip] smart_ptrs.rst updates continued; also updating classes.rst, advanced/classes.rst
1 parent c807ec3 commit 76f4da3

File tree

3 files changed

+101
-91
lines changed

3 files changed

+101
-91
lines changed

docs/advanced/classes.rst

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -125,6 +125,32 @@ extend ``Animal``, but not ``Dog``: see :ref:`virtual_and_inheritance` for the
125125
necessary steps required to providing proper overriding support for inherited
126126
classes.
127127

128+
To enable safely passing a ``std::unique_ptr`` to a trampoline object between
129+
Python and C++,
130+
131+
1. the C++ type (``Animal`` above) must be wrapped with ``py::classh``
132+
(see :ref:`smart_holder`), and
133+
134+
2. the trampoline helper class must inherit from
135+
``py::trampoline_self_life_support``.
136+
137+
I.e. the example above needs these two changes:
138+
139+
.. code-block:: cpp
140+
141+
class PyAnimal : public Animal, public py::trampoline_self_life_support {
142+
...
143+
};
144+
145+
.. code-block:: cpp
146+
147+
py::classh<Animal, PyAnimal>(m, "Animal");
148+
149+
.. seealso::
150+
151+
A fairly minimal but complete example is in
152+
:file:`tests/test_class_sh_trampoline_unique_ptr.cpp`.
153+
128154
The Python session below shows how to override ``Animal::go`` and invoke it via
129155
a virtual method call.
130156

docs/advanced/smart_ptrs.rst

Lines changed: 67 additions & 89 deletions
Original file line numberDiff line numberDiff line change
@@ -3,66 +3,52 @@ Smart pointers & ``py::class_``
33

44
The binding generator for classes, ``py::class_``, can be passed a template
55
type that denotes a special *holder* type that is used to manage references to
6-
the object. If no such holder type template argument is given, the default for
6+
the object. If no such holder type template argument is given, the default for
77
a type ``T`` is ``std::unique_ptr<T>``.
88

9+
.. note::
10+
11+
A ``py::class_`` for a given C++ type ``T`` — and all its derived types —
12+
can only use a single holder type.
13+
14+
15+
.. _smart_holder:
16+
917
``py::smart_holder``
1018
====================
1119

1220
Starting with pybind11v3, ``py::smart_holder`` is built into pybind11. It is
13-
the recommended ``py::class_`` holder for all situations, but it is **not**
14-
the default holder, and there is no intent to make it the default holder in
15-
the future, based on the assumption that this would cause more disruption
16-
than it is worth.
17-
18-
It is extremely easy to change existing pybind11 client code to use the safer
19-
and more versatile ``py::smart_holder``. For a given C++ type ``T``, simply
20-
change
21+
the recommended ``py::class_`` holder for most situations, but it is **not**
22+
the default holder, and there are no plans to make it the default holder in
23+
the future. This is based on the assumption that such a change would cause
24+
more disruption than it is worth, especially because it is extremely easy
25+
to use the safer and more versatile ``py::smart_holder``. For a given C++
26+
type ``T``, simply change
2127

2228
* ``py::class_<T>`` to
23-
* ``py::classh<T>``
29+
30+
* ``py::classh<T>``.
2431

2532
.. note::
2633

27-
``py::classh<T>`` is simply a shortcut for ``py::class_<T, py::smart_holder>``.
34+
``py::classh<T>`` is a shortcut for ``py::class_<T, py::smart_holder>``.
2835

29-
The ``py::classh<T>`` functionality includes
36+
The ``py::classh<T>`` functionality includes the following:
3037

31-
* support for **two-way** Python/C++ conversions for both
38+
* Support for **two-way** Python/C++ conversions for both
3239
``std::unique_ptr<T>`` and ``std::shared_ptr<T>`` **simultaneously**.
33-
— In contrast, ``py::class_<T>`` only supports one-way C++-to-Python
34-
conversions for ``std::unique_ptr<T>``, or alternatively two-way
35-
Python/C++ conversions for ``std::shared_ptr<T>``, which then excludes
36-
the one-way C++-to-Python ``std::unique_ptr<T>`` conversions (this manifests
37-
itself through undefined runtime behavior, often a segmentation fault
38-
or double free).
39-
40-
* passing a Python object back to C++ via ``std::unique_ptr<T>``, safely
40+
41+
* Passing a Python object back to C++ via ``std::unique_ptr<T>``, safely
4142
**disowning** the Python object.
4243

43-
* safely passing `"trampoline"
44-
<https://pybind11.readthedocs.io/en/stable/advanced/classes.html#overriding-virtual-functions-in-python>`_
45-
objects (objects with C++ virtual function overrides implemented in
46-
Python) via ``std::unique_ptr<T>`` or ``std::shared_ptr<T>`` back to C++:
44+
* Safely passing "trampoline" objects (objects with C++ virtual function
45+
overrides implemented in Python, see :ref:`overriding_virtuals`) via
46+
``std::unique_ptr<T>`` or ``std::shared_ptr<T>`` back to C++:
4747
associated Python objects are automatically kept alive for the lifetime
4848
of the smart-pointer.
4949

50-
TODO(rwgk): Move to classes.rst
51-
52-
A pybind11 `"trampoline"
53-
<https://pybind11.readthedocs.io/en/stable/advanced/classes.html#overriding-virtual-functions-in-python>`_
54-
is a C++ helper class with virtual function overrides that transparently
55-
call back from C++ into Python. To enable safely passing a ``std::unique_ptr``
56-
to a trampoline object between Python and C++, the trampoline class must
57-
inherit from ``py::trampoline_self_life_support``, for example:
58-
59-
.. code-block:: cpp
60-
61-
class PyAnimal : public Animal, public py::trampoline_self_life_support {
62-
...
63-
};
64-
65-
A fairly minimal but complete example is :file:`tests/test_class_sh_trampoline_unique_ptr.cpp`.
50+
* Full support for ``std::enable_shared_from_this`` (`cppreference
51+
<http://en.cppreference.com/w/cpp/memory/enable_shared_from_this>`_).
6652

6753

6854
``std::unique_ptr``
@@ -71,7 +57,7 @@ A fairly minimal but complete example is :file:`tests/test_class_sh_trampoline_u
7157
This is the default ``py::class_`` holder and works as expected in most
7258
situations. However, note that the handling of base-and-derived classes
7359
involves a ``reinterpret_cast`` that has strictly speaking undefined
74-
behavior. Also note that the ``std::unique_ptr`` holder only support passing
60+
behavior. Also note that the ``std::unique_ptr`` holder only supports passing
7561
a ``std::unique_ptr`` from C++ to Python, but not the other way around. For
7662
example, this code will work as expected when using ``py::class_<Example>``:
7763

@@ -83,7 +69,7 @@ example, this code will work as expected when using ``py::class_<Example>``:
8369
8470
m.def("create_example", &create_example);
8571
86-
However, this will fail with ``py::class_<Example>`` (but work with
72+
However, this will fail with ``py::class_<Example>`` (but works with
8773
``py::classh<Example>``):
8874

8975
.. code-block:: cpp
@@ -102,11 +88,10 @@ It is possible to use ``std::shared_ptr`` as the holder, for example:
10288
10389
Compared to using ``py::classh``, there are two noteworthy disadvantages:
10490

105-
* A ``py::class_`` for any particular C++ type ``T`` (and all its derived types)
106-
can only use a single holder type. Therefore, ``std::unique_ptr<T>``
107-
cannot even be passed from C++ to Python if the ``std::shared_ptr<T>`` holder
108-
is used. This will become apparent only at runtime, often through a
109-
segmentation fault or double free.
91+
* Because a ``py::class_`` for a given C++ type ``T`` can only use a
92+
single holder type, ``std::unique_ptr<T>`` cannot even be passed from C++
93+
to Python. This will become apparent only at runtime, often through a
94+
segmentation fault.
11095

11196
* Similar to the ``std::unique_ptr`` holder, the handling of base-and-derived
11297
classes involves a ``reinterpret_cast`` that has strictly speaking undefined
@@ -118,9 +103,9 @@ Compared to using ``py::classh``, there are two noteworthy disadvantages:
118103
Custom smart pointers
119104
=====================
120105

121-
For custom smart pointer, transparent conversions can be enabled
122-
using a macro invocation similar to the following. It must be declared at the
123-
top namespace level before any binding code:
106+
For custom smart pointers (e.g. ``c10::intrusive_ptr`` in pytorch), transparent
107+
conversions can be enabled using a macro invocation similar to the following.
108+
It must be declared at the top namespace level before any binding code:
124109

125110
.. code-block:: cpp
126111
@@ -167,19 +152,28 @@ specialized:
167152
The above specialization informs pybind11 that the custom ``SmartPtr`` class
168153
provides ``.get()`` functionality via ``.getPointer()``.
169154

155+
.. note::
156+
157+
The two noteworthy disadvantages mentioned under the ``std::shared_ptr``
158+
section apply similarly to custom smart pointer holders, but there is no
159+
established safe alternative in this case.
160+
170161
.. seealso::
171162

172163
The file :file:`tests/test_smart_ptr.cpp` contains a complete example
173164
that demonstrates how to work with custom reference-counting holder types
174165
in more detail.
175166

176167

177-
Be careful to not undermine automatic lifetime management
178-
=========================================================
168+
Be careful not to accidentally undermine automatic lifetime management
169+
======================================================================
179170

180-
One potential stumbling block when using holder types is that they need to be
181-
applied consistently. Can you guess what's broken about the following binding
182-
code?
171+
``py::class_``-wrapped objects automatically manage the lifetime of the
172+
wrapped C++ object, in collaboration with the chosen holder type.
173+
When wrapping C++ functions involving raw pointers, care needs to be taken
174+
to not inadvertently transfer ownership, resulting in multiple Python
175+
objects acting as owners, causing heap-use-after-free or double-free errors.
176+
For example:
183177

184178
.. code-block:: cpp
185179
@@ -188,7 +182,7 @@ code?
188182
class Parent {
189183
public:
190184
Parent() : child(std::make_shared<Child>()) { }
191-
Child *get_child() { return child.get(); } /* Hint: ** DON'T DO THIS ** */
185+
Child *get_child() { return child.get(); } /* DANGER */
192186
private:
193187
std::shared_ptr<Child> child;
194188
};
@@ -198,7 +192,7 @@ code?
198192
199193
py::class_<Parent, std::shared_ptr<Parent>>(m, "Parent")
200194
.def(py::init<>())
201-
.def("get_child", &Parent::get_child);
195+
.def("get_child", &Parent::get_child); /* PROBLEM */
202196
}
203197
204198
The following Python code will cause undefined behavior (and likely a
@@ -210,34 +204,18 @@ segmentation fault).
210204
211205
print(Parent().get_child())
212206
213-
The problem is that ``Parent::get_child()`` returns a pointer to an instance of
214-
``Child``, but the fact that this instance is already managed by
215-
``std::shared_ptr<...>`` is lost when passing raw pointers. In this case,
216-
pybind11 will create a second independent ``std::shared_ptr<...>`` that also
217-
claims ownership of the pointer. In the end, the object will be freed **twice**
218-
since these shared pointers have no way of knowing about each other.
219-
220-
There are two ways to resolve this issue:
221-
222-
1. For types that are managed by a smart pointer class, never use raw pointers
223-
in function arguments or return values. In other words: always consistently
224-
wrap pointers into their designated holder types (such as
225-
``std::shared_ptr<...>``). In this case, the signature of ``get_child()``
226-
should be modified as follows:
227-
228-
.. code-block:: cpp
229-
230-
std::shared_ptr<Child> get_child() { return child; }
231-
232-
2. Adjust the definition of ``Child`` by specifying
233-
``std::enable_shared_from_this<T>`` (see cppreference_ for details) as a
234-
base class. This adds a small bit of information to ``Child`` that allows
235-
pybind11 to realize that there is already an existing
236-
``std::shared_ptr<...>`` and communicate with it. In this case, the
237-
declaration of ``Child`` should look as follows:
238-
239-
.. _cppreference: http://en.cppreference.com/w/cpp/memory/enable_shared_from_this
240-
241-
.. code-block:: cpp
242-
243-
class Child : public std::enable_shared_from_this<Child> { };
207+
Part of the ``/* PROBLEM */`` here is that pybind11 falls back to using
208+
``return_value_policy::take_ownership`` as the default (see
209+
:ref:`return_value_policies`). The fact that the ``Child`` instance is
210+
already managed by ``std::shared_ptr<Child>`` is lost. Therefore pybind11
211+
will create a second independent ``std::shared_ptr<Child>`` that also
212+
claims ownership of the pointer, eventually leading to heap-use-after-free
213+
or double-free errors.
214+
215+
There are various ways to resolve this issue, either by changing
216+
the ``Child`` or ``Parent`` C++ implementations (e.g. using
217+
``std::enable_shared_from_this<Child>`` as a base class for
218+
``Child``, or adding a member function to ``Parent`` that returns
219+
``std::shared_ptr<Child>``), or if that is not feasible, by using
220+
``return_value_policy::reference_internal``. What is the best approach
221+
depends on the exact situation.

docs/classes.rst

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -37,8 +37,14 @@ The binding code for ``Pet`` looks as follows:
3737
:class:`class_` creates bindings for a C++ *class* or *struct*-style data
3838
structure. :func:`init` is a convenience function that takes the types of a
3939
constructor's parameters as template arguments and wraps the corresponding
40-
constructor (see the :ref:`custom_constructors` section for details). An
41-
interactive Python session demonstrating this example is shown below:
40+
constructor (see the :ref:`custom_constructors` section for details).
41+
42+
.. note::
43+
44+
Starting with pybind11v3, it is recommended to use `py::classh` in most
45+
situations. See :ref:`smart_holder` for more information.
46+
47+
An interactive Python session demonstrating this example is shown below:
4248

4349
.. code-block:: pycon
4450

0 commit comments

Comments
 (0)