Обычно разработчики библиотек C, которые используют такие обратные вызовы, предоставляют некоторый способ связать переменную состояния с обратным вызовом.Часто аргумент void*
.Некоторые библиотеки принимают этот указатель состояния при передаче обратного вызова и передают указатель в функцию обратного вызова, например, обычно это делает WinAPI, см. EnumWindows .Другие библиотеки позволяют помещать эту вещь в некоторый объект, который они передают в обратный вызов, например, libpng делает это с API-функциями png_set_write_fn
и png_get_io_ptr
.
Если после прочтения доступной документации вы пришли к выводу, что это не такдля вашей библиотеки, и вы не можете или не хотите обращаться за поддержкой к автору библиотеки, это означает, что вам нужно быть более креативным.
Один из обходных путей - использование хэш-карты для связи файлов с контейнерами.Например:
static std::unordered_map<File*, Container*> s_containers;
Свяжите файл с контейнером до RegisterCallback
, и при обратном вызове ищите указатель файла, чтобы найти контейнер.Подумайте о потоке, возможно, вам нужно защитить статическую хеш-карту с помощью мьютекса.Также подумайте об обработке исключений, возможно, вам нужен класс RAII для регистрации в конструкторе / отмене регистрации в деструкторе.
Другой, гораздо более простой, но более ограниченный метод, использует спецификатор класса памяти thread_local, представленный в C ++ / 11, объявить
static thread_local Container* s_container;
И использовать его в обратном вызове.Если ваша библиотека блокирует IO и внутренне не использует многопоточность, есть хороший шанс, что это будет работать нормально.Но все же вам нужно обрабатывать ошибки, то есть сбрасывать глобальную переменную на nullptr
, когда контейнер выходит из области видимости.
Обновление: Если вы можете изменить библиотеку, сделать это намного лучшечем оба обходных пути.Передайте еще один аргумент void*
в RegisterCallback и измените обработчик на typedef void(*FileHandler_t)(File* handle, void* context);
Если вы используете библиотеку из C ++, обычно рекомендуется реализовать обратный вызов как частный статический метод и передать указатель this
в библиотеку.Это позволит вам вызывать методы экземпляра в обратном вызове, сохраняя при этом внутреннее состояние вашего класса скрытым.