Указатели на метод экземпляра должны вызываться для экземпляра.Поскольку libevent является библиотекой C, она не предоставляет механизм для непосредственного связывания экземпляра и метода экземпляра, поэтому вам придется делать это самостоятельно.Различные функции создания событий libevent позволяют передавать произвольные данные в качестве аргумента обратного вызова.Указатель экземпляра может быть передан через этот аргумент, либо напрямую, либо упакован в класс с другими аргументами, если обратный вызов принимает дополнительные данные.Обратный вызов события может быть свободной функцией или статическим методом;какой подход выбрать, зависит от ответственности класса (в смысле SOLID, с одинарной ответственностью).
Пример с использованием статического метода и без передачи дополнительных данных:
class A {
public:
A(struct event_base *);
bool start_timer();
static void invoke_timer_handler(evutil_socket_t fd, short events, void *ctx);
void handle_timeout(evutil_socket_t fd, short events);
protected:
struct event_base *evbase;
struct event *timer;
};
A::A(struct event_base *event_base) : evbase(event_base), timer(NULL) {}
bool A::start_timer() {
// not thread safe.
if (! timer) {
timer = evtimer_new(evbase, &A::invoke_timer_handler, this);
return true;
}
return false;
}
void A::invoke_timer_handler(evutil_socket_t fd, short events, void *ctx) {
(static_cast<A*>(ctx))->handle_timeout(fd, events);
}
void A::handle_timeout(evutil_socket_t fd, short events) {
...
if (evtimer_del(timer)) {
// error deleting event
...
} else {
timer=NULL;
}
}
В примеретак как A::handle_timeout
вызывается только из A::invoke_timer_handler
, его можно сделать частным или защищенным.
В примере очень простое управление памятью.В общем случае код должен обеспечивать наличие экземпляра (и других аргументов обратного вызова, если аргумент обратного вызова не просто A*
) в течение всего времени существования события, чтобы предотвратить ошибки доступа.Также следует убедиться, что экземпляр не просочился, когда событие больше не требуетсяЕсли экземпляр владеет событием, управление памятью является относительно простым.Параллельность может также добавить усложнение, которое влияет на управление памятью.
Существующие реализации на уровне кода анонимных функций (например, boost :: lambda) и предстоящие лямбда-выражения из C ++ 11 полагаются на оператор вызова функции (operator()
), который не поддерживается в простом C. Таким образом, анонимные функции не подходят для использования в качестве обратных вызовов libevent или любых других обратных вызовов библиотеки C.