在没有Marshal.Copy或Unsafe的情况下在C ++中更新C#数组 [英] Updating a C# array inside C++ without Marshal.Copy or Unsafe

查看:98
本文介绍了在没有Marshal.Copy或Unsafe的情况下在C ++中更新C#数组的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我想更新在C#中创建的数组,然后将指向该数组的指针传递给C ++,并让C ++填充索引,以供在C#中使用.现在,我正在使用Marshal.Copy()完成此任务,但是我想避免可能不必要的复制,并回叫c ++释放数组.这有可能吗?

I am wanting to update an array that was created inside C#, and then pass a pointer to that array over to C++ and let C++ populate the indexes, to be used back in C#. Right now I am Using a Marshal.Copy() to accomplish this task, but I would like to avoid the potentially unnecessary copy, and call back to c++ to release the array. Is this even possible?

这些数组是浮点数和整数,用于几何网格数据.

These array are floats and ints, for geometric mesh data.

我当前的用法(正在工作而不是我想使用的) C#

My current usage (working and not what I want to use) C#

    IntPtr intptr=new IntPtr();
    int count = 0;
    PopulateArray(ref intptr, ref count);
    float[] resultVertices = new float[count];
    Marshal.Copy(intptr, resultVertices, 0, count);

C ++

extern "C" __declspec(dllexport) bool PopulateArray(float** resultVerts, int* resultVertLength){

    *resultVerts = new float[5]{0.123f, 3.141529f, 127.001f, 42.42f, 0};
    int myX = 5;
    *resultVertLength = myX;
    return true;
}

推荐答案

使用C ++代码更新托管C#数组的唯一安全方法是固定该数组.否则,垃圾收集器有可能在本机代码运行时尝试移动数组.您可以使用GCHandle对象来完成此操作.

The only safe way to have C++ code update a managed C# array is to pin the array. Otherwise, it's possible for the garbage collector to try to move the array while the native code is running. You can do this with a GCHandle object.

int count = 5; 
float[] resultVertices = new float[count];

GCHandle handle = GCHandle.Alloc(resultVertices, GCHandleType.Pinned);
IntPtr address = handle.AddrOfPinnedObject();

PopulateArray(address, count);

handle.Free();


它也可以使用不安全的代码来完成,这样阅读和记忆起来会更加直观:


It can also be done with unsafe code, which is somewhat more intuitive to read and remember:

int count = 5; 
float[] resultVertices = new float[count];
unsafe 
{
    fixed(float* ptr = resultVertices)
    {
        PopulateArray(ptr, count);
    }
}


另一种替代方法是让C#分配非托管内存块并将其传递给C ++方法.这比您所做的要好,因为您没有将分配/取消分配的责任放在C ++库代码中,而是将所有这些都保留在C#中.我知道您想避免麻烦,但有时复制比固定对象更有效,但这取决于它们的大小.我建议您进行性能测试,以确定最适合您的情况.


Another alternative is to have C# allocate an unmanaged chunk of memory and pass that to the C++ method. This is better than what you're doing because you are not placing the responsibility of allocation/deallocation in the C++ library code and instead keeping that all in your C#. I know you want to avoid the coy but sometimes doing the copy is more performant than pinning objects, but it depends on how large they are. I recommend you do performance testing to determine which is best for your situation.

int count = 5; 
float[] resultVertices = new float[count];
IntPtr unmanagedMemory = Marshal.AllocHGlobal(count * Marshal.SizeOf(typeof(float)));
PopulateArray(unmanagedMemory, count);
Marshal.Copy(unmanagedMemory, resultVertices, 0, count);

在所有这些情况下,您都应该将C ++代码设置为像这样操作:

In all these scenarios you should set your C++ code to operate like this:

extern "C" __declspec(dllexport) bool PopulateArray(float* resultVerts, int vertLength)
{
    resultVerts[0] = 0.123f;
    // fill out the rest of them any way you like.
    return true;
}

如果数组大小是可变的,那么我建议使用一个单独的C ++方法来计算大小并返回该大小,而不是让C ++方法分配内存.

If the array size is variable, then I recommend having a separate C++ method that calculates the size and returns it rather than having the C++ method allocate the memory.

这篇关于在没有Marshal.Copy或Unsafe的情况下在C ++中更新C#数组的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
相关文章
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆