How to write a C wrapper for delete that would be fast yet free any type given to it with out telling it what type

StackOverflow https://stackoverflow.com/questions/22584956

Question

have a whole list of C wrappers for OpenCV C++ functions like the one below. And all of them return a "new". I can't change them because they are becoming part of OpenCV and it would make my library perfect to have a consistently updated skeleton to wrap around.

Mat* cv_create_Mat() {
    return new Mat();
}

I can't rewrite the C wrapper for the C++ function so I wrote a delete wrapper like the one below,The memory I'm trying to free is a Mat*, Mat is an OpenCV c++ class...and the delete wrapper below works. There is absolutely no memory leakage at all.

I have a lot of other C wrappers for OpenCV C++ functions, though, that return a new pointer...there is at least 10 or 15 and my intention is to not have to write a separate delete wrapper for all of them. If you can show me how to write one delete wrapper that would free any pointer after having it not have to be told which type to free and fast too that would be awesome.

Those are my intentions and I know you great programmers can help me with that solution:)...in a nutshell...I have CvSVMParams*, Brisk*, RotatedRect*, CVANN_MLP* pointers there are a few others as well that all need to be free'd with one wrapper...one go to wrapper for C++'s delete that would free anything...Any help at this is greatly valued.

void delete_ptr(void* ptr) {
    delete (Mat*)ptr;
}

Edit: I'd need one of the two of you who I sent the messages to, to tell me exactly how to run your posted code...The registry version doesn't work when I place in Emacs g++ above the main and run with Free(cv_create_Mat); a new Mat* creator and stub gets 5 error message running the same way. I need exact compile instructions. My intention is to be able to compile this to .so file You have really a lot of attention to this post though and I do appreciate it..Thank you

Was it helpful?

Solution 4

Generic operations like this can only be implemented in C by removing type information (void*) or by individually ensuring all of the wrapper functions exist.

C's ABI doesn't allow function overloading, and the C++ delete keyword is exactly the sort of generic wrapper you are asking for.

That said, there are things you can do, but none of them are any simpler than what you are already proposing. Any generic C++ code you write will be uncallable from C.

You could add members to your objects which know how to destroy themselves, e.g.

class CVersionOfFoo : public Foo { ... static void deleter(CVersionOfFoo* p) { delete p; } };

But that's not accessible from C.

Your last option is to set up some form of manual registry, where objects register their pointer along with a delete function. But that's going to be more work and harder to debug than just writing wrappers.

--- EDIT ---

Registry example; if you have C++11:

#include <functional>
#include <map>

/* not thread safe */
typedef std::map<void*, std::function<void(void*)>> ObjectMap;
static ObjectMap s_objectMap;

struct Foo {
    int i;
};

struct Bar {
    char x[30];
};

template<typename T>
T* AllocateAndRegister() {
    T* t = new T();
    s_objectMap[t] = [](void* ptr) { delete reinterpret_cast<T*>(ptr); };
    return t;
}

Foo* AllocateFoo() {
    return AllocateAndRegister<Foo>();
}

Bar* AllocateBar() {
    return AllocateAndRegister<Bar>();
}

void Free(void* ptr) {
    auto it = s_objectMap.find(ptr);
    if (it != s_objectMap.end()) {
        it->second(ptr); // call the lambda
        s_objectMap.erase(it);
    }
}

If you don't have C++11... You'll have to create a delete function.

As I said, it's more work than the wrappers you were creating.

It's not a case of C++ can't do this - C++ is perfectly capable of doing this, but you're trying to do this in C and C does not provide facilities for doing this automatically.

OTHER TIPS

How about this, and then let the compiler deal with all the specializations:

template <typename T>
void delete_ptr(T *ptr) {
    delete ptr;
}

The delete operator doesn't just free memory, it also calls destructors, and it has to be called on a typed pointer (not void*) so that it knows which class's destructor to call. You'll need a separate wrapper for each type.

For POD types that don't have destructors, you can allocate with malloc() instead of new, so that the caller can just use free().

I would advise against having a generic delete_ptr function.

Since creation and deletion come in pairs, I would create one for creation and for deletion of specific types.

Mat* cv_create_Mat();
void cv_delete_Mat(Mat*);

If you do this, there will be less ambiguity about the kind of object you are dealing with. Plus, the implementation of cv_delete_Mat(Mat*) will be less error prone and has to assume less.

void cv_delete_Mat(Mat* m)
{
  delete m;
}

The core problem is that delete in C++ requires a type, and passing a pointer through a C interface loses that type. The question is how to recover that type in a generic way. Here are some choices.

Bear in mind that delete does two things: call the destructor and free the memory.

  1. Separate functions for each type. Last resort, what you're trying to avoid.
  2. For types that have a trivial destructor, you can cast your void pointer to anything you like because all it does it free the memory. That reduces the number of functions. [This is undefined behaviour, but it should work.]
  3. Use run-time type information to recover the type_info of the pointer, and then dynamic cast it to the proper type to delete.
  4. Modify your create functions to store the pointer in a dictionary with its type_info. On delete, retrieve the type and use it with dynamic cast to delete the pointer.

For all that I would probably use option 1 unless there were hundreds of the things. You could write a C++ template with explicit instantiation to reduce the amount of code needed, or a macro with token pasting to generate unique names. Here is an example (edited):

#define stub(T) T* cv_create_ ## T() { return new T(); } \
              void cv_delete_ ## T(void *p) { delete (T*)p; }
stub(Mat);
stub(Brisk);

One nice thing about the dictionary approach is for debugging. You can track new and delete at run-time and make sure they match correctly. I would pick this option if the debugging was really important, but it takes more code to do.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top