Ale*_*son 2 c++ member-function-pointers libevent
我试图将一个成员函数传递给libevent,它应被视为回调.
#include <event.h>
class A
{
public:
void eventcb(evutil_socket_t fd, short events, void *ctx) { }
};
static void global_eventcb(evutil_socket_t fd, short events, void *ctx) { }
typedef void (A::*mthd)(evutil_socket_t, short, void*);
int main(void)
{
struct event_base *evbase = event_base_new();
mthd eventcb = &A::eventcb;
A *instance = new A;
(instance->*eventcb)(NULL, 0, NULL);
struct event *timer1 = evtimer_new(evbase, global_eventcb, NULL);
struct event *timer2 = evtimer_new(evbase, (instance->*eventcb), NULL);
return 0;
}
Run Code Online (Sandbox Code Playgroud)
我可以在A类中成功创建一个指向eventcb的方法指针,并在A的实例上调用它(第20行).
此外,在第22行传递全局函数(如在C中一样)也可以正常工作.
但是,在第23行,我尝试将我的方法指针传递给libevent,当我编译它时,我得到以下错误(使用clang编译器)
example.cpp:23:25: error: no matching function for call to 'event_new'
struct event *timer2 = evtimer_new(evbase, (instance->*eventcb), NULL);
^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
In file included from example.cpp:1:
In file included from /usr/local/include/event.h:71:
/usr/local/include/event2/event.h:749:40: note: instantiated from:
#define evtimer_new(b, cb, arg) event_new((b), -1, 0, (cb), (arg))
^~~~~~~~~
/usr/local/include/event2/event.h:833:15: note: candidate function not viable: no know conversion from '<bound member function type>' to 'event_callback_fn'
(aka 'void (*)(int, short, void *)') for 4th argument
struct event *event_new(struct event_base *, evutil_socket_t, short, event_callback_fn, void *);
^
1 error generated.
Run Code Online (Sandbox Code Playgroud)
我究竟做错了什么?
实例方法指针需要调用实例.由于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;
}
}
Run Code Online (Sandbox Code Playgroud)
在该示例中,由于A::handle_timeout仅从内部调用A::invoke_timer_handler,因此可以将其设置为私有或受保护.
该示例具有非常基本的内存管理.通常,代码必须确保实例(以及其他回调参数,如果回调参数不仅仅是a A*)在事件的生命周期内存在,以防止访问错误.它还应确保在不再需要事件时实例不会泄漏.如果实例拥有该事件,则内存管理相对简单.并发还会增加影响内存管理的复杂性.
匿名函数(例如boost :: lambda)的现有代码级实现和来自C++ 11的即将发布的lambda表达式依赖于函数调用operator(operator()),它在普通C中不受支持.因此,匿名函数不适合用作libevent.回调或任何其他C库回调.
| 归档时间: |
|
| 查看次数: |
4629 次 |
| 最近记录: |