如何在堆上分配委托?
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"
}
但永远不要忘记,这是一个不安全的操作,您可能会破坏您的应用程序,甚至意外地引入任意代码执行。特别是如果您的委托上下文指针超出范围并被释放,您可能会遇到重大的不可调试问题。
例如,在这种情况下,您不应在主函数外部调用堆分配的委托,因为它很可能包含指向主函数当前堆栈帧的指针,该指针在离开后变得无效。
如何堆分配委托并获取指向它的指针?
我希望能够将它转换为 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"
}
但永远不要忘记,这是一个不安全的操作,您可能会破坏您的应用程序,甚至意外地引入任意代码执行。特别是如果您的委托上下文指针超出范围并被释放,您可能会遇到重大的不可调试问题。
例如,在这种情况下,您不应在主函数外部调用堆分配的委托,因为它很可能包含指向主函数当前堆栈帧的指针,该指针在离开后变得无效。