如何在堆上分配委托?

How do I allocate a delegate on the heap?

如何堆分配委托并获取指向它的指针?

我希望能够将它转换为 void 指针并返回,这样我就可以将它存储在异构数组中。

a delegate in D,类似于动态数组,是一个简单的结构体,有2个指针域。它具有以下字段:

  • .ptr 这是上下文指针(this 引用、闭包、栈帧指针)
  • .funcptr 也就是函数指针

因此,如果您绝对可以确保在调用序列化委托时上下文指针不会被破坏(最好在 class this 引用上,这意味着最常见的成员函数a class),你可以只用这两个 void* 值在堆上存储一个结构,或者复制它的字节,然后将它反序列化回委托。

示例:

alias MyDelegate = void delegate();

void main()
{
    int local;
    MyDelegate dlg = () { import std.stdio; writeln("delegate ", local); };

    // T.sizeof gives the size of a variable on the stack, so we get the size
    // of the delegate summing together context pointer and function pointer
    // (and potentially additional ABI things depending on the compiler/target)
    // `.dup` copies the bytes from the stack stored for the delegate to the
    // heap, but it doesn't pin the context pointer or anything similar which
    // would however make this a safer operation.
    auto heap = (cast(ubyte*)&dlg)[0 .. MyDelegate.sizeof].dup.ptr;

    local = 5;

    callHeapDlg(heap);
}

void callHeapDlg(ubyte* heap)
{
    // This could be a potentially unsafe cast if casting to some other delegate!
    // You might be casting away safety attributes or other things. Best to
    // restrict the type of the delegate you convert to heap from the start.
    // Simply recreates the delegate by casting a pointer to the bytes you have
    // copied to a pointer to a delegate object and then dereferencing it.
    // This copies the pointers from the heap back to the stack here.
    auto dlg = *(cast(MyDelegate*) heap);

    dlg(); // prints "delegate 5"
}

Try it online

但永远不要忘记,这是一个不安全的操作,您可能会破坏您的应用程序,甚至意外地引入任意代码执行。特别是如果您的委托上下文指针超出范围并被释放,您可能会遇到重大的不可调试问题。

例如,在这种情况下,您不应在主函数外部调用堆分配的委托,因为它很可能包含指向主函数当前堆栈帧的指针,该指针在离开后变得无效。

https://dlang.org/spec/abi.html#delegates