Skip to content

Commit

Permalink
docs: focus on py::smart_holder instead of py::classh
Browse files Browse the repository at this point in the history
Signed-off-by: Henry Schreiner <[email protected]>
  • Loading branch information
henryiii committed Feb 28, 2025
1 parent 1e646c9 commit 7dc507e
Show file tree
Hide file tree
Showing 8 changed files with 27 additions and 24 deletions.
4 changes: 2 additions & 2 deletions docs/advanced/cast/stl.rst
Original file line number Diff line number Diff line change
Expand Up @@ -169,8 +169,8 @@ macro must be specified at the top level (and outside of any namespaces), since
it adds a template instantiation of ``type_caster``. If your binding code consists of
multiple compilation units, it must be present in every file (typically via a
common header) preceding any usage of ``std::vector<int>``. Opaque types must
also have a corresponding ``class_`` declaration to associate them with a name
in Python, and to define a set of available operations, e.g.:
also have a corresponding ``py::class_`` declaration to associate them with a
name in Python, and to define a set of available operations, e.g.:

.. code-block:: cpp
Expand Down
13 changes: 7 additions & 6 deletions docs/advanced/classes.rst
Original file line number Diff line number Diff line change
Expand Up @@ -139,7 +139,7 @@ classes.
To enable safely passing a ``std::unique_ptr`` to a trampoline object between
Python and C++,

1. the C++ type (``Animal`` above) must be wrapped with ``py::classh``
1. the C++ type (``Animal`` above) must be wrapped with ``py::class<..., py::smart_holder>``
(see :ref:`smart_holder`), and

2. the trampoline helper class must inherit from
Expand All @@ -155,7 +155,7 @@ I.e. the example above needs these two changes:
.. code-block:: cpp
py::classh<Animal, PyAnimal>(m, "Animal");
py::class_<Animal, PyAnimal, py::smart_holder>(m, "Animal");
.. seealso::

Expand Down Expand Up @@ -587,9 +587,10 @@ pybind11. The underlying issue is that the ``std::unique_ptr`` holder type that
is responsible for managing the lifetime of instances will reference the
destructor even if no deallocations ever take place. In order to expose classes
with private or protected destructors, it is possible to override the holder
type via a holder type argument to ``class_``. Pybind11 provides a helper class
``py::nodelete`` that disables any destructor invocations. In this case, it is
crucial that instances are deallocated on the C++ side to avoid memory leaks.
type via a holder type argument to ``py::class_``. Pybind11 provides a helper
class ``py::nodelete`` that disables any destructor invocations. In this case,
it is crucial that instances are deallocated on the C++ side to avoid memory
leaks.

.. code-block:: cpp
Expand Down Expand Up @@ -908,7 +909,7 @@ Multiple Inheritance

pybind11 can create bindings for types that derive from multiple base types
(aka. *multiple inheritance*). To do so, specify all bases in the template
arguments of the ``class_`` declaration:
arguments of the ``py::class_`` declaration:

.. code-block:: cpp
Expand Down
2 changes: 1 addition & 1 deletion docs/advanced/misc.rst
Original file line number Diff line number Diff line change
Expand Up @@ -200,7 +200,7 @@ However, it can be acquired as follows:
.def("bark", &Dog::bark);
Alternatively, you can specify the base class as a template parameter option to
``class_``, which performs an automated lookup of the corresponding Python
``py::class_``, which performs an automated lookup of the corresponding Python
type. Like the above code, however, this also requires invoking the ``import``
function once to ensure that the pybind11 binding code of the module ``basic``
has been executed:
Expand Down
17 changes: 9 additions & 8 deletions docs/advanced/smart_ptrs.rst
Original file line number Diff line number Diff line change
Expand Up @@ -23,19 +23,20 @@ backward compatibility it is **not** the default holder, and there are no
plans to make it the default holder in the future.

It is extremely easy to use the safer and more versatile ``py::smart_holder``:
simply change
simply add ``py::smart_holder`` to ``py::class_``:

* ``py::class_<T>`` to

* ``py::classh<T>``.
* ``py::class_<T, py::smart_holder>``.

.. note::

``py::classh<T>`` is a shortcut for ``py::class_<T, py::smart_holder>``.
— The ``h`` in ``py::classh`` comes from **smart_holder** but is condensed
for brevity.
A shorthand, ``py::classh<T>``, is provided for ``py::class_<T,
py::smart_holder>``. The ``h`` in ``py::classh`` comes from
**smart_holder** but is condensed for brevity; it is the same number of
characters as ``py::class_``.

The ``py::classh<T>`` functionality includes the following:
The ``py::smart_holder`` functionality includes the following:

* Support for **two-way** Python/C++ conversions for both
``std::unique_ptr<T>`` and ``std::shared_ptr<T>`` **simultaneously**.
Expand Down Expand Up @@ -72,7 +73,7 @@ For example, the following code works as expected with ``py::class_<Example>``:
m.def("create_example", &create_example);
However, this will fail with ``py::class_<Example>`` (but works with
``py::classh<Example>``):
``py::class_<Example, py::smart_holder>``):

.. code-block:: cpp
Expand All @@ -95,7 +96,7 @@ It is possible to use ``std::shared_ptr`` as the holder, for example:
py::class_<Example, std::shared_ptr<Example> /* <- holder type */>(m, "Example");
Compared to using ``py::classh``, there are two noteworthy disadvantages:
Compared to using ``py::class_<Example, py::smart_holder>``, there are two noteworthy disadvantages:

* Because a ``py::class_`` for a given C++ type ``T`` can only use a
single holder type, ``std::unique_ptr<T>`` cannot even be passed from C++
Expand Down
5 changes: 3 additions & 2 deletions docs/classes.rst
Original file line number Diff line number Diff line change
Expand Up @@ -41,8 +41,9 @@ constructor (see the :ref:`custom_constructors` section for details).

.. note::

Starting with pybind11v3, it is recommended to use `py::classh` in most
situations. See :ref:`smart_holder` for more information.
Starting with pybind11v3, it is recommended to include `py::smart_holder`
if you plan to support conversions to C++ smart pointers. See
:ref:`smart_holder` for more information.

An interactive Python session demonstrating this example is shown below:

Expand Down
2 changes: 1 addition & 1 deletion docs/reference.rst
Original file line number Diff line number Diff line change
Expand Up @@ -68,7 +68,7 @@ Convenience functions converting to Python types

.. _extras:

Passing extra arguments to ``def`` or ``class_``
Passing extra arguments to ``def`` or ``py::class_``
================================================

.. doxygengroup:: annotations
Expand Down
6 changes: 3 additions & 3 deletions include/pybind11/cast.h
Original file line number Diff line number Diff line change
Expand Up @@ -1062,9 +1062,9 @@ struct move_only_holder_caster<
value = sh_load_helper.get_void_ptr_or_nullptr();
return;
}
pybind11_fail(
"Passing `std::unique_ptr<T>` from Python to C++ requires `py::classh` (with T = "
+ clean_type_id(typeinfo->cpptype->name()) + ")");
pybind11_fail("Passing `std::unique_ptr<T>` from Python to C++ requires `py::class_<T, "
"py::smart_holder>` (with T = "
+ clean_type_id(typeinfo->cpptype->name()) + ")");
}

template <typename T_>
Expand Down
2 changes: 1 addition & 1 deletion tests/test_class.py
Original file line number Diff line number Diff line change
Expand Up @@ -54,7 +54,7 @@ def test_pass_unique_ptr():
with pytest.raises(RuntimeError) as execinfo:
m.pass_unique_ptr(obj)
assert str(execinfo.value).startswith(
"Passing `std::unique_ptr<T>` from Python to C++ requires `py::classh` (with T = "
"Passing `std::unique_ptr<T>` from Python to C++ requires `py::class_<T, py::smart_holder>` (with T = "
)
assert "ToBeHeldByUniquePtr" in str(execinfo.value)

Expand Down

0 comments on commit 7dc507e

Please sign in to comment.