-2

I am trying to delete C++ pointer from C# and I do not know what I am doing wrong. Simply application crashes when I am trying to delete the Pointer.

In C# I have

IntPtr jointAreaPointer = IntPtr.Zero;

that holds a reference from c++ pointer that I conver to double array

   double[][] polylinePoints = FromNative(ref jointAreaPointer, numberOfPairs, jointAreaCountPointerFlatArray);

public static double[][] FromNative(ref IntPtr data, int m, int[] n)
{
    var matrix = new double[m][];

    for (int i = 0; i < m; i++)
    {
        int c = n[i] * 3;

        matrix[i] = new double[c];
        Marshal.Copy(Marshal.ReadIntPtr(data), matrix[i], 0, c);
        data = (IntPtr)(data.ToInt64() + IntPtr.Size);
    }

    return matrix;
}

I get the values from the array.

Then I try to delete the nested array pointer:

ReleaseNestedDouble(jointAreaPointer, numberOfPairs);

[DllImport(dllName, CallingConvention = CallingConvention.Cdecl)]
internal static extern void ReleaseNestedDouble(IntPtr arr,int count, bool isArray = true); // release input coordinates

That looks like this in c++ and crashes immediately when looping:

PINVOKE void ReleaseNestedDouble(double** arr, int count, bool isArray) {
    for (int i = 0; i < count; i++) {
        delete[](arr[i]);
    }
    delete[](arr);
}
Petras
  • 163
  • 1
  • 1
  • 12
  • No, in C++ I have allocated 2D array, in C# I just read the array and then I want to release the memory – Petras Aug 23 '21 at 21:15
  • @Petras, that sounds fairly similar to https://stackoverflow.com/questions/31417688/passing-a-vector-array-from-unmanaged-c-to-c-sharp/31418919#31418919. You can't use `new` and `delete` cross allocator and expect it to work. – Mitch Aug 23 '21 at 21:16
  • Well, you're advancing `jointAreaPointer` in `FromNative`, so the thing you are ultimately passing to `ReleaseNestedDouble` is a pointer past the end of the array. – GSerg Aug 23 '21 at 21:22

2 Answers2

3

In FromNative(ref IntPtr data, ...) your pointer data is passed by reference, and is advanced, so when calling FromNative(ref jointAreaPointer,..) your variable jointAreaPointer changes.

Later you reuse jointAreaPointer in ReleaseNestedDouble() but it does not point anymore where it pointed during the allocation.

prog-fh
  • 13,492
  • 1
  • 15
  • 30
0

.Net and C++ have different allocators and memory models. You can pass things back and forth between them, but not allocate from one and release on the other (using typed allocations). You can access native allocators from C# (e.g.: Marshal.AllocHGlobal and Marshal.AllocCoTaskMem) then use the corresponding native free methods (LocalFree and FreeCoTaskMem) - but you cannot use delete with the standard C++ allocator.

We can't see in your question how you are calling ReleaseNestedDouble - nor what is allocating the initial data. See Passing a vector/array from unmanaged C++ to C# for an example of how to do native allocations with C# consumers. Though that question refers to a vector, the process for a array would be the same.

Mitch
  • 21,223
  • 6
  • 63
  • 86
  • The first paragraph is correct per se, but is not relevant to this question. The second paragraph is incorrect because the C# signature shown for `ReleaseNestedDouble` will correctly pass the pointer to the native `ReleaseNestedDouble`. – GSerg Aug 23 '21 at 21:30
  • @GSerg - I agree regarding ReleaseNestedDouble. I was referring to `FromNative` on the basis that it was some sort of allocator - but rereading I see that is not the case. – Mitch Aug 23 '21 at 21:43