Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Python ctypes, C++ object destruction

Tags:

c++

python

ctypes

Consider the following python ctypes - c++ binding:

// C++
class A
{
public:
    void someFunc();
};

A* A_new() { return new A(); }
void A_someFunc(A* obj) { obj->someFunc(); }
void A_destruct(A* obj) { delete obj; }

# python
from ctypes import cdll

libA = cdll.LoadLibrary(some_path)

class A:
    def __init__(self):
        self.obj = libA.A_new()

    def some_func(self):
        libA.A_someFunc(self.obj)

What's the best way to delete the c++ object, when the python object is not needed any more.

[edit] I added the delete function that was suggested, however the problem remains by whom and when the function is called. It should be as convenient as possible.

like image 362
tauran Avatar asked Sep 16 '10 08:09

tauran


3 Answers

You could implement the __del__ method, which calls a destructor function you would have to define:

C++

class A
{
public:
    void someFunc();
};

A* A_new() { return new A(); }
void delete_A(A* obj) { delete obj; }
void A_someFunc(A* obj) { obj->someFunc(); }

Python

from ctypes import cdll

libA = cdll.LoadLibrary(some_path)

class A:
    def __init__(self):
        fun = libA.A_new
        fun.argtypes = []
        fun.restype = ctypes.c_void_p
        self.obj = fun()

    def __del__(self):
        fun = libA.delete_A
        fun.argtypes = [ctypes.c_void_p]
        fun.restype = None
        fun(self.obj)

    def some_func(self):
        fun = libA.A_someFunc
        fun.argtypes = [ctypes.c_void_p]
        fun.restype = None
        fun(self.obj)

Also note that you left out the self parameter on the __init__ method. Futhermore, you have to specify the return type/argument type explicitly, because ctypes defaults to 32 bit integers, while a pointer is likely 64 bits on modern systems.

Some think __del__ is evil. As an alternative, you can use with syntax:

class A:
    def __init__(self):
        fun = libA.A_new
        fun.argtypes = []
        fun.restype = ctypes.c_void_p
        self.obj = fun()

    def __enter__(self):
        return self

    def __exit__(self, exc_type, exc_val, exc_tb):
        fun = libA.delete_A
        fun.argtypes = [ctypes.c_void_p]
        fun.restype = None
        fun(self.obj)

    def some_func(self):
        fun = libA.A_someFunc
        fun.argtypes = [ctypes.c_void_p]
        fun.restype = None
        fun(self.obj)

with A() as a:
    # Do some work
    a.some_func()
like image 184
Marcelo Cantos Avatar answered Oct 06 '22 00:10

Marcelo Cantos


In general, dlls should provide a method for cleaning up object that they created. That way, memory allocation is encapsulated within the dll. This means, your dll should probably expose a method like void A_delete(A*).

like image 43
Björn Pollex Avatar answered Oct 05 '22 22:10

Björn Pollex


Export a function from the DLL the frees the object. You have to do this in order to ensure that the same memory management mechanism is used to free the object that was in charge when the object was allocated.

like image 38
Jim Brissom Avatar answered Oct 05 '22 23:10

Jim Brissom