Skip to content

Missing cast from const unique_ptr& #2904

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 2 commits into from
Mar 17, 2021

Conversation

rhaschke
Copy link
Contributor

The issue mentioned in #2901 (the compiler complaining about impossible casting from const unique_ptr& to unique_ptr&&) originates from a missing cast implementation. I added a dummy implementation (69769a9) and the compiler errors are gone.

IMO, casting from a const unique_ptr& should distinguish the following two cases:

  1. If the instance is already registered, it should be returned with an increased refcount.
  2. Otherwise, a new instance should be created (which holder?), which must not be deleted or moved. Is that possible at all?

@@ -698,6 +698,9 @@ struct smart_holder_type_caster<std::unique_ptr<T, D>> : smart_holder_type_caste

return inst.release();
}
static handle cast(const std::unique_ptr<T, D> &src, return_value_policy policy, handle parent) {
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Aha :-)
That makes everything clear immediately, thanks!
Initial thought: This is very similar to static handle cast(const T *src, ...). We could mimic that implementation, or maybe even reuse? The easy case is that an instance exists already and we just incref as you suggest. Or there needs to be return_value_policy::reference_internal or an explicit keep_alive.
Is there a chance you could help with that implementation? It's unlikely that I can prioritize working on this myself anytime soon, unless I hit on a use case in PyCLIF (difficult to predict). But I will review & merge very quickly if you take the lead.
My revised suggestion for a separate new unit test name iff we cannot reuse static handle cast(const T *src, ...): test_class_sh_const_unique_return
Keeping the tests separate helps minimizing merge issues (between master, drake, smart_holder) and is best practice IMO regardless.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done. Thanks for the hint to cast(const T*). Regarding the unit test: I think we should have a unit test in any case.
Do you suggest to move the test into a new file, named test_class_sh_const_unique_return.cpp or to include a test named test_class_sh_const_unique_return into some existing file?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hm. I don't understand why CI fails, while locally it works fine. Need to investigate later...

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Oh, sorry to be ambiguous: I was thinking of test_class_sh_const_unique_return.cpp and .py.
I think I also want to add a few lines to test_class_sh_basic.cpp and .py, but that's a small enough effort I could squeeze that in myself.

@rhaschke rhaschke force-pushed the cast-unique-ptr-const-reference branch 2 times, most recently from c1c2590 to 5ef0563 Compare March 16, 2021 06:45
@@ -698,6 +698,9 @@ struct smart_holder_type_caster<std::unique_ptr<T, D>> : smart_holder_type_caste

return inst.release();
}
static handle cast(const std::unique_ptr<T, D> &src, return_value_policy policy, handle parent) {
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Oh, sorry to be ambiguous: I was thinking of test_class_sh_const_unique_return.cpp and .py.
I think I also want to add a few lines to test_class_sh_basic.cpp and .py, but that's a small enough effort I could squeeze that in myself.

@rhaschke rhaschke force-pushed the cast-unique-ptr-const-reference branch from 5ef0563 to fa41723 Compare March 16, 2021 11:00
@rwgk
Copy link
Collaborator

rwgk commented Mar 16, 2021

I looked at one of the CI failures: https://github.com/pybind/pybind11/pull/2904/checks?check_run_id=2120821136
It looks like it's somehow falling back to move_only_holder_caster, which shouldn't be involved at all for types using the smart_holder_type_caster family.

There is a lot going on in test_smart_ptr.cpp, especially with the TYPE_CASTERS macros, which could be easily confusing. If you move the new test to a separate pair of files we have a simpler context to worry about.

About test_smart_ptr in general: it was the most special test for me to deal with. From memory, I think none of the py::class_ in there uses smart_holder, even if you build with ENABLE_SMART_HOLDER_AS_DEFAULT.

My general approach for the existing tests was: if a holder is specified explicitly, keep it that way, with or without ENABLE_SMART_HOLDER_AS_DEFAULT. If a derived py::class_ uses a custom holder, make the std::unique_ptr holder for the base explicit. — That way I could be sure that I'm not trying to run tests designed specifically for the old holder handling for the new smart_holder code. The smart_holder code has independent dedicated tests in the test_class_sh_* files.

@rhaschke
Copy link
Contributor Author

Thanks for these hints. I will move my tests into test_class_sh_* files. I also noticed that I should use py::classh instead of py::class_ in order to get smart holders. The CI failures are probably due to the fact that CI doesn't use ENABLE_SMART_HOLDER_AS_DEFAULT but requires manual smart_holder triggering via py::classh.

@rwgk
Copy link
Collaborator

rwgk commented Mar 16, 2021

The CI failures are probably due to the fact that CI doesn't use ENABLE_SMART_HOLDER_AS_DEFAULT but requires manual smart_holder triggering via py::classh.

Oh yes, that's another stumbling stone. I have PR #2879 for that purpose. I keep reusing it, by rebasing it on whatever I want to test at the moment.

@rwgk
Copy link
Collaborator

rwgk commented Mar 16, 2021

Hi Robert, I just merged #2902 into the smart_holder branch. You may want to rebase this PR.

@rhaschke rhaschke force-pushed the cast-unique-ptr-const-reference branch 3 times, most recently from 1439591 to e24ca2c Compare March 16, 2021 14:51
@rhaschke
Copy link
Contributor Author

This should be ready for a fresh review. I added several new test cases, one of them still failing. Particularly, this roundtrip test attempts to pass a unique_ptr from python to C++ as a const reference and returning the very same reference to Python again. IMO, this should leave the original python instance alive and just increase the reference count. However, the instance is moved to C++ and thus disowned in Python.

@rwgk
Copy link
Collaborator

rwgk commented Mar 16, 2021

IMO, this should leave the original python instance alive and just increase the reference count. However, the instance is moved to C++ and thus disowned in Python.

I think (!) you could leverage the dynamic_cast that I just merged (#2902) to achieve that for types that inherit from virtual_overrider_self_life_support, but without something like that I think it's not possible: when you get the same pointer value back, you don't know if it's still the same object, or a different newly allocated one that just happens to have the same address.

@rhaschke
Copy link
Contributor Author

CI still failing, because windows moves more often... Will fix.

@rhaschke rhaschke force-pushed the cast-unique-ptr-const-reference branch from e24ca2c to 4c76ada Compare March 16, 2021 15:14
@rhaschke
Copy link
Contributor Author

CI passes! 🎉

@rwgk
Copy link
Collaborator

rwgk commented Mar 17, 2021

Thanks Robert! I'll merge this now.

@rwgk rwgk merged commit 784092d into pybind:smart_holder Mar 17, 2021
@github-actions github-actions bot added the needs changelog Possibly needs a changelog entry label Mar 17, 2021
@rwgk rwgk removed the needs changelog Possibly needs a changelog entry label Mar 17, 2021
@rhaschke rhaschke deleted the cast-unique-ptr-const-reference branch March 17, 2021 01:25
@EricCousineau-TRI EricCousineau-TRI added the smart holder See: https://github.com/pybind/pybind11/blob/smart_holder/README_smart_holder.rst label Apr 26, 2021
rwgk added a commit to rwgk/pybind11 that referenced this pull request Mar 5, 2025
…major and/or influential contributors to smart_holder branch

* pybind#2904 by @rhaschke was merged on Mar 16, 2021
* pybind#3012 by @rhaschke was merged on May 28, 2021
* pybind#3039 by @jakobandersen was merged on Jun 29, 2021
* pybind#3048 by @Skylion007 was merged on Jun 18, 2021
* pybind#3588 by @virtuald was merged on Jan 3, 2022
* pybind#3633 by @wangxf123456 was merged on Jan 25, 2022
* pybind#3635 by @virtuald was merged on Jan 26, 2022
* pybind#3645 by @wangxf123456 was merged on Jan 25, 2022
* pybind#3796 by @wangxf123456 was merged on Mar 10, 2022
* pybind#3807 by @wangxf123456 was merged on Mar 18, 2022
* pybind#3838 by @wangxf123456 was merged on Apr 15, 2022
* pybind#3929 by @tomba was merged on May 7, 2022
* pybind#4031 by @wangxf123456 was merged on Jun 27, 2022
* pybind#4343 by @wangxf123456 was merged on Nov 18, 2022
* pybind#4381 by @wangxf123456 was merged on Dec 5, 2022
* pybind#4539 by @wangxf123456 was merged on Feb 28, 2023
* pybind#4609 by @wangxf123456 was merged on Apr 6, 2023
* pybind#4775 by @wangxf123456 was merged on Aug 3, 2023
* pybind#4921 by @iwanders was merged on Nov 7, 2023
* pybind#4924 by @iwanders was merged on Nov 6, 2023
* pybind#5401 by @msimacek was merged on Oct 8, 2024

Co-authored-by: Aaron Gokaslan <aaronGokaslan@gmail.com>
Co-authored-by: Dustin Spicuzza <dustin@virtualroadside.com>
Co-authored-by: Ivor Wanders <iwanders@users.noreply.github.com>
Co-authored-by: Jakob Lykke Andersen <Jakob@caput.dk>
Co-authored-by: Michael Šimáček <michael.simacek@oracle.com>
Co-authored-by: Robert Haschke <rhaschke@users.noreply.github.com>
Co-authored-by: Tomi Valkeinen <tomi.valkeinen@iki.fi>
Co-authored-by: Xiaofei Wang <6218006+wangxf123456@users.noreply.github.com>
rwgk added a commit that referenced this pull request Mar 5, 2025
* Pure `git merge --squash smart_holder` (no manual interventions).

* Remove ubench/ directory.

* Remove include/pybind11/smart_holder.h

* [ci skip] smart_ptrs.rst updates [WIP/unfinished]

* [ci skip] smart_ptrs.rst updates continued; also updating classes.rst, advanced/classes.rst

* Remove README_smart_holder.rst

* Restore original README.rst from master

* [ci skip] Minimal change to README.rst, to leave a hint that this is pybind11v3

* [ci skip] Work in ChatGPT suggestions.

* Change macro name to PYBIND11_RUN_TESTING_WITH_SMART_HOLDER_AS_DEFAULT_BUT_NEVER_USE_IN_PRODUCTION_PLEASE

* Add a note pointing to the holder reinterpret_cast.

* Incorporate suggestion by @virtuald: #5542 (comment)

* Systematically change most py::class_ to py::classh under docs/

* Remove references to README_smart_holder.rst

This should have been part of commit eb550d0.

* [ci skip] Fix minor oversight (``class_`` -> ``py::class_``) noticed by chance.

* [ci skip] Resolve suggestion by @virtuald

#5542 (comment)

* [ci skip] Apply suggestions by @timohl (thanks!)

* #5542 (comment)
* #5542 (comment)
* #5542 (comment)

* Replace `classh : class_` inhertance with `using`, as suggested by @henryiii

#5542 (comment)

* Revert "Systematically change most py::class_ to py::classh under docs/"

This reverts commit ac9d31e.

* docs: focus on py::smart_holder instead of py::classh

Signed-off-by: Henry Schreiner <henryschreineriii@gmail.com>

* Restore minor general fixes that got lost when ac9d31e was reverted.

* Remove `- smart_holder` from list of branches in all .github/workflows

* Extend classh note to explain whitespace noise motivation.

* Suggest `py::smart_holder` for "most situations for safety"

* Add back PYBIND11_HAS_INTERNALS_WITH_SMART_HOLDER_SUPPORT

This define was
* introduced with #5286
* removed with #5531

It is has been in use here:
* https://github.com/pybind/pybind11_protobuf/blob/f02a2b7653bc50eb5119d125842a3870db95d251/pybind11_protobuf/native_proto_caster.h#L89-L101

Currently pybind11 unit tests for the two holder caster backwards compatibility traits

* `copyable_holder_caster_shared_ptr_with_smart_holder_support_enabled`
* `move_only_holder_caster_unique_ptr_with_smart_holder_support_enabled`

are missing.

* Add py::trampoline_self_life_support to all trampoline examples under docs/.

Address suggestion by @timohl:

* #5542 (comment)

Add to the "please think twice" note: the overhead for safety is likely in the noise.

Also fix a two-fold inconsistency introduced by revert-commit 1e646c9:

1.

py::trampoline_self_life_support is mentioned in a note, but is missing in the example right before.

2.

The section starting with

    To enable safely passing a ``std::unique_ptr`` to a trampoline object between

is obsolete.

* Fix whitespace accident (indentation) introduced with 1e646c9

Apparently the mis-indentation was introduced when resolving merge conflicts for what became 1e646c9

* WHITESPACE CHANGES ONLY in README.rst (list of people that made significant contributions)

* Add Ethan Steinberg to list of people that made significant contributions (for completeness, unrelated to smart_holder work).

* [ci skip] Add to list of people that made significant contributions: major and/or influential contributors to smart_holder branch

* #2904 by @rhaschke was merged on Mar 16, 2021
* #3012 by @rhaschke was merged on May 28, 2021
* #3039 by @jakobandersen was merged on Jun 29, 2021
* #3048 by @Skylion007 was merged on Jun 18, 2021
* #3588 by @virtuald was merged on Jan 3, 2022
* #3633 by @wangxf123456 was merged on Jan 25, 2022
* #3635 by @virtuald was merged on Jan 26, 2022
* #3645 by @wangxf123456 was merged on Jan 25, 2022
* #3796 by @wangxf123456 was merged on Mar 10, 2022
* #3807 by @wangxf123456 was merged on Mar 18, 2022
* #3838 by @wangxf123456 was merged on Apr 15, 2022
* #3929 by @tomba was merged on May 7, 2022
* #4031 by @wangxf123456 was merged on Jun 27, 2022
* #4343 by @wangxf123456 was merged on Nov 18, 2022
* #4381 by @wangxf123456 was merged on Dec 5, 2022
* #4539 by @wangxf123456 was merged on Feb 28, 2023
* #4609 by @wangxf123456 was merged on Apr 6, 2023
* #4775 by @wangxf123456 was merged on Aug 3, 2023
* #4921 by @iwanders was merged on Nov 7, 2023
* #4924 by @iwanders was merged on Nov 6, 2023
* #5401 by @msimacek was merged on Oct 8, 2024

Co-authored-by: Aaron Gokaslan <aaronGokaslan@gmail.com>
Co-authored-by: Dustin Spicuzza <dustin@virtualroadside.com>
Co-authored-by: Ivor Wanders <iwanders@users.noreply.github.com>
Co-authored-by: Jakob Lykke Andersen <Jakob@caput.dk>
Co-authored-by: Michael Šimáček <michael.simacek@oracle.com>
Co-authored-by: Robert Haschke <rhaschke@users.noreply.github.com>
Co-authored-by: Tomi Valkeinen <tomi.valkeinen@iki.fi>
Co-authored-by: Xiaofei Wang <6218006+wangxf123456@users.noreply.github.com>

---------

Signed-off-by: Henry Schreiner <henryschreineriii@gmail.com>
Co-authored-by: Henry Schreiner <henryschreineriii@gmail.com>
Co-authored-by: Aaron Gokaslan <aaronGokaslan@gmail.com>
Co-authored-by: Dustin Spicuzza <dustin@virtualroadside.com>
Co-authored-by: Ivor Wanders <iwanders@users.noreply.github.com>
Co-authored-by: Jakob Lykke Andersen <Jakob@caput.dk>
Co-authored-by: Michael Šimáček <michael.simacek@oracle.com>
Co-authored-by: Robert Haschke <rhaschke@users.noreply.github.com>
Co-authored-by: Tomi Valkeinen <tomi.valkeinen@iki.fi>
Co-authored-by: Xiaofei Wang <6218006+wangxf123456@users.noreply.github.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
smart holder See: https://github.com/pybind/pybind11/blob/smart_holder/README_smart_holder.rst
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants