Dear Pybind11 developers, i would like to report a strange case which on a surface looks like a situation when C++ fail to retain ownership of classes defined in Python and derived from C++ base classes.
Below is a minimal example to reproduce this. Note that Python script have --bug command line argument which allow to trigger a bug. And if option is not supplied then code work as expected without any errors.
In short: issues seems to arise when derived class is created in C++ by a 'clone' method. It looks like after creation 'Python' portion of Snake class will get immediately deleted unless it explicitly stored in one of Python variables.
When --bug is supplied execution terminated with error message:
Snake.clone!
Traceback (most recent call last):
File "inheritance-clone.py", line 34, in <module>
example.clone_and_call_go(a)
RuntimeError: Tried to call pure virtual function "Animal::go"
#include<pybind11/pybind11.h>classAnimal {
public:virtual~Animal() { }
virtual std::string go(int n_times) = 0;
virtual std::shared_ptr<Animal> clone() = 0;
};
std::string clone_and_call_go(std::shared_ptr<Animal> animal) {
auto new_animal = animal->clone();
return new_animal->go(3);
}
classPyAnimal : publicAnimal {
public:/* Inherit the constructors */using Animal::Animal;
/* Trampoline (need one for each virtual function) */
std::string go(int n_times) override {
PYBIND11_OVERLOAD_PURE(
std::string, /* Return type */
Animal, /* Parent class */
go, /* Name of function in C++ (must match Python name) */
n_times /* Argument(s) */
);
}
std::shared_ptr<Animal> clone() override {
PYBIND11_OVERLOAD_PURE(
std::shared_ptr<Animal>,
Animal,
clone
);
}
};
namespacepy= pybind11;
PYBIND11_MODULE(example, m) {
py::class_<Animal, std::shared_ptr<Animal>, PyAnimal>(m, "Animal")
.def(py::init<>())
.def("go", &Animal::go)
.def("clone", &Animal::clone)
;
m.def("clone_and_call_go", &clone_and_call_go);
}importargparseimportexampleclassSnake(example.Animal):
def__init__(self, bug):
#super().__init__()example.Animal.__init__(self)
self.copies_= []
self.bug_=bugdefgo(self, n_times):
s='Snake.go({})'.format(n_times)
print(s)
returnsdefclone(self):
print('Snake.clone!')
copy=Snake(bug=self.bug_)
ifnotself.bug_:
self.copies_.append(copy)
returncopyif__name__=="__main__":
parser=argparse.ArgumentParser()
parser.add_argument("--bug", action="store_true", help="Disables the workaround, showcases the bug")
args=parser.parse_args()
a=Snake(args.bug)
example.clone_and_call_go(a)
Dear Pybind11 developers, i would like to report a strange case which on a surface looks like a situation when C++ fail to retain ownership of classes defined in Python and derived from C++ base classes.
Below is a minimal example to reproduce this. Note that Python script have
--bugcommand line argument which allow to trigger a bug. And if option is not supplied then code work as expected without any errors.In short: issues seems to arise when derived class is created in C++ by a 'clone' method. It looks like after creation 'Python' portion of
Snakeclass will get immediately deleted unless it explicitly stored in one of Python variables.When
--bugis supplied execution terminated with error message: