Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Cleanup all c++ objects after python script is finished

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?

like image 524
Andrei R. Avatar asked Nov 08 '22 12:11

Andrei R.


1 Answers

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
like image 130
HarshGiri Avatar answered Nov 14 '22 22:11

HarshGiri