Calling to a C++ class instance method from a UV callback

671 views
Skip to first unread message

Iñaki Baz Castillo

unread,
Mar 7, 2014, 1:40:52 PM3/7/14
to li...@googlegroups.com
Hi, I'm trying to figure out how to use UV in my C++ project in a way that the UV callbacks are instance methods of my classes.

I know that a UV callback must be a static method (and not a C++ class member method) so I use std::bind. However it fails:


-------------------------------------------------------------------
// Worker constructor.
Worker::Worker() {
  this->number = 42;

  this->loop = new uv_loop_t;
  uv_loop_init(this->loop);

  this->idle = new uv_idle_t;
  uv_idle_init(this->loop, this->idle);

  auto callback = std::bind(&Worker::Callback, this, std::placeholders::_1, std::placeholders::_2);
  uv_idle_start(this->loop, callback);

  uv_run(this->loop, UV_RUN_DEFAULT);
}


// Callback to be called by the UV idle.
void Worker::Callback(uv_idle_t* handle, int status) {
  // do something with Worker instance members:
  printf("my number is %d\n", this->number);
}
-------------------------------------


Unfortunately this does not compile (G++ 4.8 with -std=c++11):

Worker.cpp: In member function 'void Worker::Run()':
Worker.cpp:77:36: error: cannot convert 'std::_Bind<std::_Mem_fn<void (Worker::*)(uv_idle_s*, int)>(Worker*, std::_Placeholder<1>, std::_Placeholder<2>)>' to 'uv_idle_cb {aka void (*)(uv_idle_s*, int)}' for argument '2' to 'int uv_idle_start(uv_idle_t*, uv_idle_cb)'
uv_idle_start(this->loop, callback);



I have a working solution that I just don't like:

---------------------------------------------
std::function<void(uv_idle_t*, int)> callback;

void wrapper(uv_idle_t* handle, int status) {
  callback(handle, status);
}


Worker::Worker() {
  this->number = 42;

  this->loop = new uv_loop_t;
  uv_loop_init(this->loop);

  this->idle = new uv_idle_t;
  uv_idle_init(this->loop, this->idle);

  auto callback = std::bind(&Worker::Callback, this, std::placeholders::_1, std::placeholders::_2);
  uv_idle_start(this->loop, wrapper); // Note that here I pass wrapper instead of callback.

  uv_run(this->loop, UV_RUN_DEFAULT);
}


// Callback to be called by the UV idle.
void Worker::Callback(uv_idle_t* handle, int status) {
  // do something with Worker instance members:
  printf("my number is %d\n", this->number);
}
---------------------------------------------



Do I miss something in my first (and not working) approach?
NOTE: I would prefer not to store "this" (the pointer to the current Worker instance) into the handler->data field.


Thanks a lot.

Iñaki Baz Castillo

unread,
Mar 7, 2014, 2:02:16 PM3/7/14
to li...@googlegroups.com
2014-03-07 19:40 GMT+01:00 Iñaki Baz Castillo <i...@aliax.net>:
> I have a working solution that I just don't like:
>
> ---------------------------------------------
> std::function<void(uv_idle_t*, int)> callback;
>
> void wrapper(uv_idle_t* handle, int status) {
> callback(handle, status);
> }
>
>
> Worker::Worker() {
> this->number = 42;
>
> this->loop = new uv_loop_t;
> uv_loop_init(this->loop);
>
> this->idle = new uv_idle_t;
> uv_idle_init(this->loop, this->idle);
>
> auto callback = std::bind(&Worker::Callback, this, std::placeholders::_1,
> std::placeholders::_2);
> uv_idle_start(this->loop, wrapper); // Note that here I pass wrapper
> instead of callback.
>
> uv_run(this->loop, UV_RUN_DEFAULT);
> }
>
>
> // Callback to be called by the UV idle.
> void Worker::Callback(uv_idle_t* handle, int status) {
> // do something with Worker instance members:
> printf("my number is %d\n", this->number);
> }
> ---------------------------------------------


Well, this second "working" solution is not thread safe at all, so also invalid.

I've been told in the libuv IRC channel that, indeed, std::bind
returns a C++ object, something that cannot be "casted" into a
function pointer, and thus, my first approach is just not possible.

So I must play with the handle's data structure and store there my
"this" pointer.


Best regards.



--
Iñaki Baz Castillo
<i...@aliax.net>
Reply all
Reply to author
Forward
0 new messages