是否有可能在没有pin_ptr的情况下将托管字节数组转换为本机结构,所以不要过多地破坏GC?

时间:2015-05-07 10:27:28

标签: c++-cli

只有使用array<Byte>^,AFAIK,才能将托管struct投放到某个非托管pin_ptr,例如:

void Example(array<Byte>^ bfr) {
    pin_ptr<Byte> ptr = &bfr[0];
    auto data = reinterpret_cast<NonManagedStruct*>(ptr);
    data->Header = 7;
    data->Length = sizeof(data);
    data->CRC = CalculateCRC(data);
}

但是,以任何方式使用interior_ptr

我更倾向于使用低级方式处理托管数据(使用union s,struct - 位字段等等),而无需固定数据 - 我可能是持有此数据已有相当长的时间,并且不想骚扰GC

澄清:

我不想将托管数据复制到本机和后台(因此这里不能选择Marshaling方式...)

1 个答案:

答案 0 :(得分:2)

您可能无法使用pin_ptr骚扰GC - 与GCHandle不同,它非常轻量级。

GCHandle::Alloc(someObject, GCHandleType::Pinned)实际上会将对象注册为固定在GC中。这使您可以在较长的时间内和函数调用之间固定对象,但GC必须跟踪该对象。

另一方面,pin_ptr被转换为IL代码中的固定本地。 GC没有收到有关它的通知,但它会在集合期间看到该对象仅固定 。也就是说,当在堆栈上查找对象引用时,它会注意到它的固定状态。

如果确实想要,您可以通过以下方式访问堆栈内存:

[StructLayout(LayoutKind::Explicit, Size = 256)]
public value struct ManagedStruct
{
};

struct NativeStruct
{
    char data[256];
};

static void DoSomething()
{
    ManagedStruct managed;
    auto nativePtr = reinterpret_cast<NativeStruct*>(&managed);
    nativePtr->data[42] = 42;
}

这里根本没有固定,但这只是因为托管结构存储在堆栈中,因此首先不可重定位。 / p>

这是一个令人费解的例子,因为你可以写:

static void DoSomething()
{
    NativeStruct native;
    native.data[42] = 42;
}

...并且编译器将为您执行类似的技巧。