我有一个非托管类,它接受一个指向内存的指针作为它的存储空间。
例如
class MemBlock
{
void* mpMemoryBlock;
// Various other variables that manipulate the memory block goes here.
public:
MemBlock( void* pMemoryBlock ) :
mpMemoryBlock( pMemoryBlock )
{
}
// A load of code that does operation on the memory block goes here.
};
现在我正在尝试包装此类以便在 C# 中使用。显然,我希望能够将类似 float[]
的内容传递给类(class)。显而易见的事情是使用包装类中的 cli::pin_ptr
。
public ref class MemBlockWrapper
{
MemBlock* mpMemBlock;
public:
MemBlockWrapper( array< float >^ fltArray )
{
cli::pin_ptr< float > pFltArray = &fltArray[0];
// Brilliant we can now pass this pinned array to the C++ code.
mpMemBlock = new MemBlock( (void*)pFltArray );
// Now the pin_ptr goes out of scope ...
}
}
然而,固定的 ptr 仅在 cli::pin_ptr 在范围内时才有效。构造函数退出的那一刻,我不能再保证 C++ 类拥有的内存块是真实的。
有没有办法在类的生命周期内固定一个指针?我做了很多搜索,只找到了一种使用“GCHandle”的方法,它似乎纯粹用于托管 C++(即不是 C++/CLI)。有人能指出我确定性地固定和取消固定指针的方法吗?
最佳答案
Warning: This directly answers the question, but before you try this, first read Hans' answer and make sure you really understand what's going on and still want to do it this way.
一个固定的 GCHandle
将完成这项工作,它可以从 C++/CLI 中使用。显然,只需确保 handle 是 Pinned 类型即可。
这是一个例子:
public ref class MemBlockWrapper
{
MemBlock* mpMemBlock;
System::Runtime::InteropServices::GCHandle hFltArray;
public:
MemBlockWrapper(array< float >^ fltArray)
{
hFltArray = System::Runtime::InteropServices::GCHandle::Alloc(
fltArray,
System::Runtime::InteropServices::GCHandleType::Pinned);
mpMemBlock = new MemBlock(hFltArray.AddrOfPinnedObject().ToPointer());
}
~MemBlockWrapper()
{
this->!MemBlockWrapper();
}
!MemBlockWrapper()
{
if (mpMemBlock)
{
delete mpMemBlock;
mpMemBlock = nullptr;
hFltArray.Free();
}
}
};
我添加了一个析构函数和一个终结器,这样即使您忘记处置包装器,您也可以获得 Disposable
模式以及安全清理。
关于c# - 使用 CLI 数组分配的内存作为非托管类的存储,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/34277565/