Как написать оболочку C для удаления, которая была бы быстрой, но свободной от любого типа, данного ей, без указания типа

0

имеют полный список 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 файл. У вас действительно много внимания к этому сообщению, хотя я и ценю это. Спасибо.

  • 0
    На данном этапе я думаю, что на ваш вопрос ответили. Вы должны раздать +1 или галочку. Если вам нужна помощь, чтобы ваш код работал, я предлагаю опубликовать его как новый вопрос.
Теги:
opencv
wrapper
delete-operator

5 ответов

0
Лучший ответ

Такие общие операции могут быть реализованы только на 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, не предоставляет возможности для этого автоматически.

  • 0
    Можете ли вы показать мне, как реализовать идею ручного реестра, относящуюся к опубликованному мною коду, или ссылаться на ссылку, которая выполняет ручную регистрацию в оболочках Си. Я новичок в утечках памяти, и я мог бы использовать некоторый рабочий код в качестве доказательства концепции ..
  • 0
    см. мои правки выше
Показать ещё 3 комментария
1

Я бы посоветовал не иметь общую функцию delete_ptr.

Поскольку создание и удаление попадают парами, я бы создал один для создания и для удаления определенных типов.

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

Если вы это сделаете, будет меньше двусмысленности в отношении того объекта, с которым вы имеете дело. Кроме того, реализация cv_delete_Mat(Mat*) будет менее подвержена ошибкам и должна принять меньше.

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

Как насчет этого, а затем пусть компилятор имеет дело со всеми специализациями:

template <typename T>
void delete_ptr(T *ptr) {
    delete ptr;
}
  • 1
    Это не вызывается из C; компилятор C не может создавать экземпляры шаблонов C ++.
  • 1
    C также не может использовать ключевое слово delete.
Показать ещё 3 комментария
1

Оператор delete не просто освобождает память, но и вызывает деструкторы, и его нужно вызывать на типизированном указателе (не void*), чтобы он знал, какой класс деструктор вызывает. Для каждого типа вам понадобится отдельная оболочка.

Для типов POD, у которых нет деструкторов, вы можете выделять с помощью malloc() вместо new, так что вызывающий может просто использовать free().

0

Основная проблема заключается в том, что delete в C++ требует типа, и передача указателя через интерфейс C теряет этот тип. Вопрос заключается в том, как восстановить этот тип в общем виде. Вот несколько вариантов.

Имейте в виду, что delete делает две вещи: вызовите деструктор и освободите память.

  1. Отдельные функции для каждого типа. Последнее средство, чего вы пытаетесь избежать.
  2. Для типов, которые имеют тривиальный деструктор, вы можете наложить указатель на void на все, что вам нравится, потому что все это освобождает память. Это уменьшает количество функций. [Это неопределенное поведение, но оно должно работать.]
  3. Используйте информацию типа времени выполнения для восстановления указателя типа_и указателя, а затем динамически применяйте его к соответствующему типу для удаления.
  4. Измените свои функции создания, чтобы сохранить указатель в словаре с его type_info. При удалении извлеките тип и используйте его с динамическим приложением для удаления указателя.

Для всего, что я, вероятно, использовал бы вариант 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);

Одна из приятных особенностей словарного подхода - отладка. Вы можете отслеживать новые и удалять во время выполнения и следить за их соответствием. Я бы выбрал этот вариант, если отладка была действительно важна, но для этого требуется больше кода.

  • 0
    Спасибо, что ответили мне, я ценю это, мне было интересно, можете ли вы показать мне, как сделать то, о чем вы говорили в своем ответе ... Я мог бы использовать пример из реальной жизни ... рабочую функцию, которую я могу добавить к моя библиотека и использование в качестве шаблона для выполнения других функций, я, кажется, учиться лучше всего таким образом
  • 0
    пожалуйста, смотрите последние изменения

Ещё вопросы

Сообщество Overcoder
Наверх
Меню