1

I built a C++ shared library, that exports functions for constructing, destructing and interacting with an implemented class. I want to write a wrapper class in Python, which loads the compiled .dll and wraps all the functions as a class using ctypes .

How do I wrap the destructor function of the C++ class safely so it will be called in any case (Normal Garbage Collection, Exceptions etc) ?

flxh
  • 565
  • 4
  • 19
  • 1
    You probably shouldn't be calling the destructor at all. If you are using `new` to create the object, you should call `delete` on it to destroy the object, not call the destructor. How this call can be wrapped in a function that python's ctypes will call at an appropriate time, I don't know. – user17732522 Feb 10 '22 at 16:46
  • Yes you are right. What I meant is: I have an exported function that deletes the pointer/object passed as an argument. – flxh Feb 10 '22 at 16:50

1 Answers1

1

As per Python's data model doc:

Objects are never explicitly destroyed; however, when they become unreachable they may be garbage-collected. An implementation is allowed to postpone garbage collection or omit it altogether...

...

Some objects contain references to “external” resources such as open files or windows. It is understood that these resources are freed when the object is garbage-collected, but since garbage collection is not guaranteed to happen, such objects also provide an explicit way to release the external resource, usually a close() method. Programs are strongly recommended to explicitly close such objects. The try…finally statement and the with statement provide convenient ways to do this.

So even if in most cases __del__ method of an object is being called by GC, it is not guaranteed. with statement (from PEP 343) on the other hand guarantees that if __enter__ method of the object succeeded, then __exit__ method will be called at the end of the statement, both in case of normal execution and in case of exception. (More detailed in this question)

An example could be as below, with the usage of "object-closing" context manager from PEP 343 examples, and a wrapper class with close method which calls native object's destructor:

class NativeObjectWrapper(object):
    def __init__(self):
        self.nativeObject = nativeLib.CreateInstance()
    def close(self):
        nativeLib.DestructorFunction(self.nativeObject)
        
class closing(object):
    def __init__(self, obj):
        self.obj = obj
    def __enter__(self):
        return self.obj
    def __exit__(self, *exc_info):
        try:
            close_it = self.obj.close
        except AttributeError:
            pass
        else:
            close_it()
            
#example of usage
with closing(NativeObjectWrapper()) as objectWrapper:
    ... #some usage of native wrapper
Renat
  • 7,718
  • 2
  • 20
  • 34