Преобразование указателя объекта D в void * и переход к обратному вызову - PullRequest
0 голосов
/ 31 декабря 2018

Я хочу преобразовать указатель класса D в void*, передать этот указатель void* вместе с указателем на мою функцию обратного вызова extern(C) в подпрограмму библиотеки C.

Подпрограмма библиотеки C будетвызовите мою функцию обратного вызова extern(C), которая преобразует void* обратно в указатель класса и использует объект этого класса.

Проблема: я слышал, что объекты GC могут быть перемещены в другие места (возможно, нетв текущей версии D, но в будущем).Означает ли это, что мой указатель void* может стать недействительным (больше не указывает на мой объект)?

Если проблема действительно существует, как ее решить?

Ответы [ 2 ]

0 голосов
/ 31 декабря 2018

Основано на ответе Адама Д. Руппе, но реорганизовано.

Еще лучше код 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);
   }
}
0 голосов
/ 31 декабря 2018

Вы можете сказать, что GC должен удерживать указатель как корень, и, кроме того, запретить ему перемещать его с помощью функции import core.memory; GC.addRoot(ptr);.Этот пример показывает это полностью:

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…
}
...