File tree Expand file tree Collapse file tree 1 file changed +15
-1
lines changed Expand file tree Collapse file tree 1 file changed +15
-1
lines changed Original file line number Diff line number Diff line change @@ -354,7 +354,21 @@ struct smart_holder {
354354 // Relinquish ownership only after successful construction of owner
355355 (void ) unq_ptr.release ();
356356
357- // Publish either the subobject alias (for identity/VI) or the full object.
357+ // Publish either the MI/VI subobject pointer (if provided) or the full object.
358+ // Why this is needed:
359+ // * The `owner` shared_ptr must always manage the true object start (T*).
360+ // That ensures the deleter is invoked on a valid object header, so the
361+ // virtual destructor can dispatch safely (critical on MSVC with virtual
362+ // inheritance, where base subobjects are not at offset 0).
363+ // * However, pybind11 needs to *register* and expose the subobject pointer
364+ // appropriate for the type being bound.
365+ // This pointer may differ from the T* object start under multiple/virtual
366+ // inheritance.
367+ // This is achieved by using an aliasing shared_ptr<void>:
368+ // - `owner` retains lifetime of the actual T* object start for deletion.
369+ // - `vptr` points at the adjusted subobject (mi_subobject_ptr), giving
370+ // Python the correct identity/registration address.
371+ // If no subobject pointer is passed, we simply publish the full object.
358372 if (mi_subobject_ptr) {
359373 hld.vptr = std::shared_ptr<void >(owner, mi_subobject_ptr);
360374 } else {
You can’t perform that action at this time.
0 commit comments