简体   繁体   中英

Wrapping a C++ allocated instance with pybind11

When embedding python in C++ through PyBind11, I got stuck on the following issue. Consider I generate a shared_ptr instance of an object through C++ and I then want to handover this pointer to pybind11 to generate a "shadow" python binding for it.

Here is my initial, non-working attempt:

#include <stdio.h>
#include <pybind11/pybind11.h>
#include <pybind11/embed.h>

using namespace std;
namespace py = pybind11;

class Pet 
{
public:
    Pet() {}
    void bark(void) { printf("wow!\n"); }
};

PYBIND11_PLUGIN(Pets) {
    py::module m("Pets", "Say hello to our pets");

    py::class_<Pet, shared_ptr<Pet>>(m, "Pet")
        .def("bark", &Pet::bark)
      ;
    return m.ptr();
}

int main(int argc, char *argv[])
{
  py::scoped_interpreter guard{};
  shared_ptr<Pet> pet = make_shared<Pet>();

  // How do Ι "assign" Pet.pet to the C++ pet? This compiles,
  // but throws a run time exception:
  py::globals()["pet"] = py::cast(pet);

  py::exec("pet.bark()\n");
}

So my questions are:

  • So how can I create a "shadow class" for C++ shared_ptr?
  • How can I "assign" a C++ shared_ptr to a python variable?

If you check the resulting py::object from the cast (eg by casting it to bool), you will see that the call failed. The reason is that the python does not know the class "Pet" (nor shared_ptr). You can either use the code as above and create a module from it the usual way, then import that in a main program. Or, use the EMBEDDED_MODULE feature, which is closer to what you appear to be going for.

Adjusting your example:

#include <stdio.h>
#include <pybind11/pybind11.h>
#include <pybind11/embed.h>

using namespace std;
namespace py = pybind11;

class Pet
{
public:
    Pet() {}
    void bark(void) { printf("wow!\n"); }
};

PYBIND11_EMBEDDED_MODULE(Pets, m) {
    py::class_<Pet, shared_ptr<Pet>>(m, "Pet")
        .def("bark", &Pet::bark)
    ;
}

int main(int argc, char *argv[])
{
  py::scoped_interpreter guard{};
  shared_ptr<Pet> pet = make_shared<Pet>();

  auto pets_mod = py::module::import("Pets");

  py::globals()["pet"] = py::cast(pet);
  py::exec("pet.bark()\n");
}

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM