-
Notifications
You must be signed in to change notification settings - Fork 2.2k
Description
Recently @rwgk revived the discussion on supporting movable custom types (and holders), see #2583, #2040, #1132.
I want to summarize the discussion so far and structure the problem into several subproblems, in the hope that we can focus our future discussion on the corresponding subproblems.
-
Fix segfaults due to mismatching holder types, i.e. fixing pybind11 wrapped method segfaults if a function returns
unique_ptr<T>when holder isshared_ptr<T>#1138 and C++ object is destructed before it can be used, when returned as ashared_ptrand using default holder type #1215.
pybind11 assumes that holder types are used consistently, i.e. once registered, a custom type needs to stick with its holder type, let it be the defaultunique_ptror any custom smart ptr. However, this basic assumption is not validated (yet) and thus can cause severe segfaults if users don't obey this rule.
I think Detect and fail if using mismatched holders #2644 addresses this issue in a clean and efficient manner (building on the great work Detect and fail if using mismatched holders #1161 from @jagerman) by validating holder compatibility at function/class definition time (runtime). -
Support moving (rvalue-reference arguments) for custom types, allowing to (easily) wrap functions like this:
void consume(CustomType&& object) { CustomType sink(std::move(object)); }
This doesn't work out of the box (yet), but is in principle possible already right now, employing a small wrapper function as pointed out by @YannickJadoul in [WIP] Towards a solution for custom-type rvalue arguments #2047 (comment).
My PR [WIP] Towards a solution for custom-type rvalue arguments #2047 is an initial attempt to enable this feature. However, I recently detected an open issue with this approach.
EDIT: In a rework, I hopefully fixed the move/copy semantics. See here for details. -
Support moving of holder types, i.e. ownership transfer from python to C++, allowing to wrap functions like this:
void consume(unique_ptr<CustomType>&& object) { CustomType sink(std::move(*holder.release()); }
There are two possible implementations for this: WIP: Support ownership transfer between C++ and Python with
shared_ptr<T>andunique_ptr<T>for pure C++ instances and single-inheritance instances #1146 (rather huge) and Towards a solution for rvalue holder arguments in wrapped functions #2046. However, to quote @wjakob:Transferring ownership from Python to C++ is a super-dangerous and rather unnatural (non-pythonic) operation and intentionally not supported in pybind11.
If implementing this, we need to ensure that all python object references of the moved holder are validated before
loading. For an open issues on this, see Towards a solution for rvalue holder arguments in wrapped functions #2046 (comment). -
A feature related to both 1. and 3. is the (implicit) conversion between different holder types as requested e.g. in Detect and fail if using mismatched holders #1161 (comment) and proposed in Detect and fail if using mismatched holders #1161 (comment): Instead of complaining about incompatible holder types, pybind11 should "just" auto-magically convert between them - if possible. For example,
std::shared_ptrcan be implicitly move-constructed from astd::unique_ptr, which indeed would make sense for function return values, i.e. auto-converting astd::unique_ptrreturn value into astd::shared_ptrholder.
But, in my opinion, this is the only valid use case. If 3. is in place, argument conversion can be easily handled explicitly with corresponding wrapper functions.Instead of a silently auto-converting between holders, maybe a new
return_value_policycould be used that specifies the target holder type and then - at compile time - just adds another wrapping layer to convert the return value? -
As pointed out by @YannickJadoul in [WIP] Towards a solution for custom-type rvalue arguments #2047 (comment), there are some more open issues with casters, e.g. passing containers of char * (e.g. std::vector<char *>) does not work #2245/Fix casters of STL containers with
char*#2303/[BUG] Keep pybind11 type casters alive recursively when needed #2527, or Casting from an unregistered type does not throw. #2336. -
EDIT(eric): pybind11 inheritance slicing; see [BUG] Problem when creating derived Python objects from C++ (inheritance slicing) #1333 for an example. Including it here due to current coupling to holder setup.