将 D 对象指针转换为 void* 并传递给回调
Converting a D object pointer to void* and passing to a callback
我想将 D class 指针转换为 void*
,将此 void*
指针与指向我的回调 extern(C)
函数的指针一起传递给 C 库例程.
C 库例程将调用我的回调 extern(C)
函数,该函数会将 void*
转换回 class 指针并使用此 class 的对象。
问题:我听说GC对象可能会被移动到其他位置(可能不是在当前的D版本中,而是在未来)。这是否意味着我的 void*
指针可能会变得无效(不再指向我的对象)?
如果确实存在问题,如何解决?
你可以通过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…
}
基于 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);
}
}
我想将 D class 指针转换为 void*
,将此 void*
指针与指向我的回调 extern(C)
函数的指针一起传递给 C 库例程.
C 库例程将调用我的回调 extern(C)
函数,该函数会将 void*
转换回 class 指针并使用此 class 的对象。
问题:我听说GC对象可能会被移动到其他位置(可能不是在当前的D版本中,而是在未来)。这是否意味着我的 void*
指针可能会变得无效(不再指向我的对象)?
如果确实存在问题,如何解决?
你可以通过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…
}
基于 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);
}
}