I have an application, implementing python interpreter, with custom python modules, exporting classes. Example c++ class may look like:
class MyClass {
MyClass() { cout << "created" << endl; }
~MyClass() { cout << "destroyed" << endl; }
};
Code for executing python scripts looks like:
namespace bp = boost::python;
bp::dict dict;
try {
dict = bp::dict(bp::import("__main__").attr("__dict__"));
bp::exec_file(filename, dict, dict);
} catch (bp::error_already_set &) {
// dict.clear()
PyErr_Print();
PyErr_Clear();
}
The issue is, c++ objects created from python code are not destroyed immediately after script is terminated by exception. For example, simple script is run twice:
import MyModule
myobj = MyModule.MyClass()
assert False
output I get (A):
// script launched first time
created
// script finished
// script launched second time
created
destroyed
// script finished
// Py_Finalize() is called
destroyed
output I want (B):
// script launched first time
created
// script finished
destroyed
// script launched second time
created
// script finished
destroyed
// Py_Finalize() is called
Now, the fun part. If we uncomment // dict.clear()
, behavior starts being different depending on script structure. For the abovementioned python snippet I get output B (as expected), but I still get A for script like:
import MyModule
def main():
myobj = MyModule.MyClass()
assert False
if __name__ == "__main__":
main()
How to properly delete c++ objects, created from python?
You can give ownership of c++ object to python.
Please check below example, it might work for you.
Also check the this link for more understanding of call policies.
C++ code:
class MyClass {
public:
MyClass() { cout << "created" << endl; }
~MyClass() { cout << "destroyed" << endl; }
};
MyClass* get_objectof_MyClass(){
return new MyClass();
}
BOOST_PYTHON_MODULE(MyModule)
{
class_<MyClass>("MyClass");
def("get_objectof_MyClass", get_objectof_MyClass, return_value_policy<manage_new_object>());
//using manage_new_object we are giving ownership to python side and python will clean it up when out of scope.
}
Python side code:
import MyModule
def main():
myobj = MyModule.get_objectof_MyClass()
if __name__ == "__main__":
main()
Output:
created
destroyed
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With