Delegates and C function pointers

anonymous via Digitalmars-d-learn digitalmars-d-learn at puremagic.com
Sat Nov 8 08:01:08 PST 2014


On Saturday, 8 November 2014 at 12:23:45 UTC, Nicolas Sicard
wrote:
> I would like to register a D delegate to a C API that takes a
> function pointer as a callback and a void* pointer to pass data
> to this callback.
>
> My solution is in http://dpaste.dzfl.pl/7d9b504b4b965.
>
> Is this code correct? Is there something simpler or already in
> Phobos that I have overlooked?
>
> Thanks
> -- Nicolas

I think it's a little more complicated than it needs to be.
Instead of going delegate->DelegateData*->delegate you can pass a
pointer to the delegate:

void doSomethingFromD(void delegate() dg)
{
      static extern(C) void adapter(void* ptr)
      {
          auto dg = *cast(void delegate()*)ptr;
          dg();
      }

      dosomething(&adapter, &dg);
}

&dg is fine if dosomething calls the callback before
doSomethingFromD returns.

If the callback is stored and called later on, you have to put
the delegate somewhere more lasting. And you have to make sure
that the GC doesn't collect it in the meantime. In your code
you're new-ing, but you don't keep the reference around in
D-land. The GC would happily collect the delegate then, because
it doesn't look in C-land for references.

For example, you could add all callbacks to a module level array:

void delegate()[] activeCallbacks;
void doSomethingFromD(void delegate() dg)
{
      static extern(C) void adapter(void* ptr)
      {
          auto dg = *cast(void delegate()*)ptr;
          dg();
      }

      activeCallbacks ~= dg;
      dosomething(&adapter, &activeCallbacks[$ - 1]);
}

Then when everything's done and you know that the callbacks are
not needed anymore, empty activeCallbacks so that the GC can
collect them.

Essentially, you're back to manual management, and have to think
about the life times of the callbacks.


More information about the Digitalmars-d-learn mailing list