Skip to content Skip to sidebar Skip to footer

Pybind11: Transfer Class Ownership To C++ On Construct

I'm having an issue where a python class, which is derived from a c++ base class using pybind11, is being immediately destructed (garbage collected). I would like C++ to take owne

Solution 1:

The correct (I think) way to use std::shared_ptr<A> as the A holder is to add it to class_<A...> arguments.

You also want to replace every instance of A* with std::shared_ptr<A>, and new with std::make_shared. I think non-default return policies are not needed in this case, so I have removed them; YMMV.

Working module below (with minor errors corrected).

#include<pybind11/pybind11.h>#include<memory>#include<iostream>namespace py = pybind11;

classA
{
public:
    A(){};
    A(const A&) { std::cout << "Copying A\n"; }
    virtual ~A()
    {
        std::cout << "In A::~A()\n";
    };

    virtualconstchar* SayHello(){
        constchar* x = "\n\nHello from Class A\n\n";
        return x;
    }
};

classATrampoline : public A
{
public:
    using A::A;
    constchar* SayHello()override{
        PYBIND11_OVERLOAD( constchar*,A,SayHello,);
    }
};


classB
{
public:
    B()
    {
        std::cout << "In Class B Constructor\n";
    }

    B(const B&) { std::cout << "Copying B\n"; }
    voidRun(){
        aBase = AllocateAnAClass();
        std::cout << aBase->SayHello();
    }

    virtual ~B()
    {
    }

    std::shared_ptr<A> aBase;

    virtual std::shared_ptr<A> AllocateAnAClass(){
        return std::make_shared<A>();
    }
};

classBTrampoline : public B
{
public:
    using B::B;
    std::shared_ptr<A> AllocateAnAClass()override{
        PYBIND11_OVERLOAD(std::shared_ptr<A>,B,AllocateAnAClass,);
    }
};

PYBIND11_MODULE(TestModule,m)
{
    py::class_<A,std::shared_ptr<A>, ATrampoline>(m,"A")
        .def(py::init<>())
        .def("SayHello",&A::SayHello);

    py::class_<B, BTrampoline>(m,"B")
        .def(py::init<>())
        .def("Run",&B::Run)
        .def("AllocateAnAClass",&B::AllocateAnAClass);
}

Solution 2:

py::nodelete was the solution. While n.m's answer DOES work, it would require going back and chaning all of the pointer in an existing libary to smart pointers, which isn't a viable option for me. Using py::nodelete allows me to do everything on the pybind11 side.

py::class_<A,ATramploline,std::unique_ptr<A,py::nodelete> >(m,"A")
        .def(py::init<>())
        .def("SayHello",&A::SayHello);

Post a Comment for "Pybind11: Transfer Class Ownership To C++ On Construct"