Thread overview | ||||||
---|---|---|---|---|---|---|
|
July 05, 2014 Using a delegate when interfacing with C | ||||
---|---|---|---|---|
| ||||
Hi, I'm quite new to D and I'm not able to find out what I'm doing wrong. Consider the following code: class ClientImplementation { private ProcessDelegate processDelegate; void setProcessDelegate(ProcessDelegate deleg) { this.processDelegate = deleg; extern(C) ProcessCallback callback = function int(NFrames nframes, void* data) { auto client = *(cast(ClientImplementation*) data); return client.processDelegate(nframes); }; this.setProcessCallback(callback, cast(void *) &this); } In my D wrapper for a C API I want to use delegates. The C API accepts a callback which has a generic void* parameter which can be specified when setting the callback (it will be stored and passed in the callback when it gets called... a common pattern in C APIs). So I want to use it to make delegates possible. The problem with this approach is that I get a segmentation fault on the line: auto client = *(cast(ClientImplementation*) data); as soon as the callback is called the first time. The callback is called in another thread (but this shouldn't be a problem since ClientImplementation is a class and therefore instances are created in the heap). Can somebody help me in figuring out why this happens? I also tried unsuccesfully auto client = cast(ClientImplementation*) data; |
July 05, 2014 Re: Using a delegate when interfacing with C | ||||
---|---|---|---|---|
| ||||
Posted in reply to Marco Cosentino | On Saturday, 5 July 2014 at 22:18:56 UTC, Marco Cosentino wrote: > auto client = *(cast(ClientImplementation*) data); Try just auto client = cast(ClientImplementation) data; and this.setProcessCallback(callback, cast(void *) &this); setProcessCallback(callback, cast(void*) this); > Can somebody help me in figuring out why this happens? The reason is a class this in D is already a pointer (just a hidden one) so when you do &this in a class, it is like a ClientImplementation** in C - a pointer to a (temporary) pointer. So by the time the callback runs, it is pointing to nonsense. In general, remember any class reference in D is already equivalent to a pointer in C or C++ and can be casted straight to void* without needing to take its address. |
July 05, 2014 Re: Using a delegate when interfacing with C | ||||
---|---|---|---|---|
| ||||
Posted in reply to Adam D. Ruppe | On Saturday, 5 July 2014 at 22:28:48 UTC, Adam D. Ruppe wrote:
> In general, remember any class reference in D is already equivalent to a pointer in C or C++ and can be casted straight to void* without needing to take its address.
Thanks Adam,
you're a life saver ;). It works like a charme.
|
July 06, 2014 Re: Using a delegate when interfacing with C | ||||
---|---|---|---|---|
| ||||
Posted in reply to Adam D. Ruppe | Hey Adam, an interesting aspect of what I'd like to achieve is to use compile-time reflection to generate the wrapper functions for all the delegates (there are ~ 10). The pattern is like what I presented eariler and in addition to that there are some delegates which have no return type (void). I managed to write a template like this (D is awesome): alias ProcessDelegate = int delegate(NFrames nframes); import std.traits; private template CallbackWrapper(alias T) if(isDelegate!T) { extern(C) static auto wrapper(ParameterTypeTuple!T params, void * data) { auto client = cast(ClientImplementation) data; return mixin("client." ~ __traits(identifier, T) ~ "(params)"); } } void setProcessDelegate(ProcessDelegate deleg) { processDelegate = deleg; setProcessCallback( & CallbackWrapper!(processDelegate).wrapper, cast(void *) this); } |
Copyright © 1999-2021 by the D Language Foundation