将D对象指针转换为void *并传递给回调

时间:2018-12-31 14:56:28

标签: pointers garbage-collection d void-pointers

我想将D类指针转换为void*,并将此void*指针与指向回调函数extern(C)的指针一起传递给C库例程。

C库例程将调用我的回调extern(C)函数,该函数将void*转换回类指针并使用该类的对象。

麻烦:我听说GC对象可能会移动到其他位置(可能不是当前的D版本,而是将来的版本)。这是否意味着我的void*指针可能变得无效(不再指向我的对象)?

如果问题确实存在,如何解决?

2 个答案:

答案 0 :(得分:1)

您可以告诉GC以根为根握住指针,此外,还可以使用import core.memory; GC.addRoot(ptr);函数告诉GC不要将其移到您身上。这个例子完整地展示了它:

http://dpldocs.info/experimental-docs/core.memory.GC.addRoot.html#examples

// Typical C-style callback mechanism; the passed function
// is invoked with the user-supplied context pointer at a
// later point.
extern(C) void addCallback(void function(void*), void*);

// Allocate an object on the GC heap (this would usually be
// some application-specific context data).
auto context = new Object;

// Make sure that it is not collected even if it is no
// longer referenced from D code (stack, GC heap, …).
GC.addRoot(cast(void*)context);

// Also ensure that a moving collector does not relocate
// the object.
GC.setAttr(cast(void*)context, GC.BlkAttr.NO_MOVE);

// Now context can be safely passed to the C library.
addCallback(&myHandler, cast(void*)context);

extern(C) void myHandler(void* ctx)
{
   // Assuming that the callback is invoked only once, the
   // added root can be removed again now to allow the GC
   // to collect it later.
   GC.removeRoot(ctx);
   GC.clrAttr(ctx, GC.BlkAttr.NO_MOVE);

   auto context = cast(Object)ctx;
   // Use context here…
}

答案 1 :(得分:-1)

根据亚当·鲁珀(Adam D. Ruppe)的回答,但进行了重组。

更好的OO代码:

import core.memory : GC;

class UnmovableObject {
    this() {
        //GC.addRoot(cast(void*)this); // prevents finalization
        GC.setAttr(cast(void*)this, GC.BlkAttr.NO_MOVE);
    }
    ~this() {
       //GC.removeRoot(cast(void*)this);
       GC.clrAttr(cast(void*)this, GC.BlkAttr.NO_MOVE);
   }
}