pybind / pybind/pybind11

py::cast on non-polymorphic base class pointer does not find existing derived instance

Open
#1,148 5 comments 0 reactions 0 assignees View on GitHub

Nobody has claimed this yet.

Dominant language
C++
Stars
18k
Forks
2.3k
Avg merge
5d 17h
Merged PRs (30d)
10

Description

Issue description

I'm not sure if this is a bug or just a limitation of what pybind11 can do, but it could merit at least a mention in the docs or the FAQ.

When using py::cast to convert a C++ pointer to a py::object, if the pointer has a base class type but actually points to a derived object that was created from Python, it fails to recognise that this is an existing instance and instead creates a second Python wrapper.

If the base class is made polymorphic, then everything works. However, I have a base class I don't want to be polymorphic for performance reasons.

The use case is that I need to get a Python handle to this inside a method that is being exposed to Python, for lifetime management purposes (it's a case that won't fit into the standard call policies).

Tested on v2.2.0-38-g6a81dbb.

Reproducible example code

#include <pybind11/pybind11.h>

namespace py = pybind11;

class Base {};
class A : public Base {};

PYBIND11_MODULE(variant, m) {
    py::class_<Base>(m, "Base")
        .def("show", [] (const Base &base)
        {
            py::print("I am", py::cast(&base));
        });

    py::class_<A, Base>(m, "A");

    m.def("make_a", []() -> py::object
    {
        py::object obj = py::cast(A());
        py::print("Created", obj);
        return obj;
    });
}
from variant import make_a
a = make_a()
a.show()

Output:

Created <variant.A object at 0x7fc7288b3ce0>
I am <variant.Base object at 0x7fc7288b3d18>

Expected output:

Created <variant.A object at 0x7fc7288b3ce0>
I am <variant.A object at 0x7fc7288b3ce0>

Contributor guide

Open the contributing guide

First steps

  1. Read the whole issue, then the project's contributing guide.
  2. Comment on the issue to say you are picking it up — it saves two people doing the same work.
  3. Fork the repository and make your change on a branch.
  4. Open a pull request that references the issue number.

Research direction

Start by running the supplied C++ binding and Python example to reproduce the duplicate wrapper for a non-polymorphic base pointer. Trace the py::cast path involved in converting the base pointer and compare it with the polymorphic case. Done means the existing A instance is returned, or the limitation is documented in the docs or FAQ.

Written by the indexing model from the issue text.

Assessment

Tech stack
cpp, python
Domain
api, tooling
Issue type
Bug
Difficulty
4/5
Estimated time
3-5 days
Activity status
Stale
Clarity
Mostly clear
Newbie friendliness
35/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.