имеют полный список C-оболочек для функций OpenCV C++, подобных приведенным ниже. И все они возвращают "новое". Я не могу их изменить, потому что они становятся частью OpenCV, и это сделает мою библиотеку идеальной, чтобы иметь постоянно обновляемый скелет для обертывания.
Mat* cv_create_Mat() {
return new Mat();
}
Я не могу перезаписать оболочку C для функции C++, поэтому я написал обертку для удаления, как показано ниже. Память, которую я пытаюсь освободить, - это Mat *, Mat - класс OpenCV C++... и обложка удаления ниже работает. Абсолютно никакой утечки памяти нет.
У меня есть много других C-оболочек для функций OpenCV C++, хотя они возвращают новый указатель... есть как минимум 10 или 15, и я намерен не писать отдельную обертку для всех из них. Если вы можете показать мне, как написать одну оболочку удаления, которая освободит любой указатель, после того, как ему не нужно будет говорить, какой тип будет бесплатным и быстрым, это было бы потрясающе.
Это мои намерения, и я знаю, что великие программисты могут помочь мне с этим решением:)... в двух словах... У меня есть указатели CvSVMParams *, Brisk *, RotatedRect *, CVANN_MLP *, есть еще несколько других, что все нужно быть свободным с одной оберткой... один идет в обертку для удаления C++, который освободит что-нибудь... Любая помощь в этом очень ценится.
void delete_ptr(void* ptr) {
delete (Mat*)ptr;
}
Редактировать: мне понадобится один из вас, к которому я отправил сообщения, чтобы точно рассказать мне, как запустить ваш опубликованный код... Версия реестра не работает, когда я размещаю Emacs g++ над основным и запустить с помощью Free (cv_create_Mat); новый создатель Mat * и заглушка получают 5 сообщений об ошибках, работающих одинаково. Мне нужны точные инструкции компиляции. Мое намерение состоит в том, чтобы иметь возможность компилировать это.so файл. У вас действительно много внимания к этому сообщению, хотя я и ценю это. Спасибо.
Такие общие операции могут быть реализованы только на C путем удаления информации о типе (void*
) или путем индивидуального обеспечения всех функций оболочки.
C ABI не разрешает перегрузку функции, а ключевое слово delete
C++ - это именно то, что вы запрашиваете.
Тем не менее, есть вещи, которые вы можете сделать, но ни один из них не проще, чем то, что вы уже предлагаете. Любой генерируемый вами код C++, который вы пишете, будет непригодным для C.
Вы можете добавлять членов к своим объектам, которые умеют уничтожать себя, например
class CVersionOfFoo: public Foo {... static void deleter (CVersionOfFoo * p) {delete p; } }; }};
Но это не доступно из C.
Ваш последний вариант - настроить ручную регистрацию, где объекты регистрируют свой указатель вместе с функцией удаления. Но это будет больше работы и сложнее отлаживать, чем просто писать обертки.
--- РЕДАКТИРОВАТЬ ---
Пример реестра; если у вас есть 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);
}
}
Если у вас нет C++ 11... Вам нужно будет создать функцию удаления.
Как я уже сказал, это больше работает, чем обертки, которые вы создавали.
Это не случай C++ не может этого сделать - C++ вполне способен это сделать, но вы пытаетесь сделать это в C и C, не предоставляет возможности для этого автоматически.
Я бы посоветовал не иметь общую функцию delete_ptr
.
Поскольку создание и удаление попадают парами, я бы создал один для создания и для удаления определенных типов.
Mat* cv_create_Mat();
void cv_delete_Mat(Mat*);
Если вы это сделаете, будет меньше двусмысленности в отношении того объекта, с которым вы имеете дело. Кроме того, реализация cv_delete_Mat(Mat*)
будет менее подвержена ошибкам и должна принять меньше.
void cv_delete_Mat(Mat* m)
{
delete m;
}
Как насчет этого, а затем пусть компилятор имеет дело со всеми специализациями:
template <typename T>
void delete_ptr(T *ptr) {
delete ptr;
}
Оператор delete
не просто освобождает память, но и вызывает деструкторы, и его нужно вызывать на типизированном указателе (не void*
), чтобы он знал, какой класс деструктор вызывает. Для каждого типа вам понадобится отдельная оболочка.
Для типов POD, у которых нет деструкторов, вы можете выделять с помощью malloc()
вместо new
, так что вызывающий может просто использовать free()
.
Основная проблема заключается в том, что delete
в C++ требует типа, и передача указателя через интерфейс C теряет этот тип. Вопрос заключается в том, как восстановить этот тип в общем виде. Вот несколько вариантов.
Имейте в виду, что delete
делает две вещи: вызовите деструктор и освободите память.
Для всего, что я, вероятно, использовал бы вариант 1, если бы не было сотен вещей. Вы можете написать шаблон C++ с явным инстанцированием, чтобы уменьшить количество требуемого кода или макрос с вставкой маркера для создания уникальных имен. Вот пример (отредактирован):
#define stub(T) T* cv_create_ ## T() { return new T(); } \
void cv_delete_ ## T(void *p) { delete (T*)p; }
stub(Mat);
stub(Brisk);
Одна из приятных особенностей словарного подхода - отладка. Вы можете отслеживать новые и удалять во время выполнения и следить за их соответствием. Я бы выбрал этот вариант, если отладка была действительно важна, но для этого требуется больше кода.