Read Write C ++ Динамические массивы в C # (InteropServices)

У меня есть класс C ++, который имеет заголовок (matrixheader.h) такой, что:

#pragma once

class M
{
public:
M(int m,int n);
void MSet(int m,int n,double d);
double MGet(int m,int n);
~M();
private:
double** mat;
};

Класс определяется следующим образом (matrixbody.cpp): Он встроен в платформу Win32.

#pragma once
#include "matrixhead.h"
M::M(int m,int n)
{
mat = new double*[m];
for (int i = 0; i < m; i++)
{
mat[i] = new double[n];
}
}

void M::MSet(int m,int n,double d)
{
mat[m][n] = d;
}

double M::MGet(int m,int n)
{
double d = mat[m][n];
return d;
}

M::~M()
{
delete[] mat;
}

Я сделал обертку для класса следующим образом (matrixwrapper.cpp): Оболочка также встроена в платформу Win32.

#include "matrixhead.h"#include "matrixbody.cpp"
extern "C" __declspec(dllexport) void* Make(int m,int n)
{
M o(m,n);
return &o;
}

extern "C" __declspec(dllexport) void setData(void* mp,int m,int n,double d)
{
M* ap = (M*)mp;
M a = *ap;
a.MSet(m,n,d);
}

extern "C" __declspec(dllexport) double getData(void* mp,int m,int n)
{
M* bp = (M*)mp;
M b = *bp;
double d = b.MGet(m,n);
return d;
}

Я импортирую класс в C # и пытаюсь вызвать методы C ++ dl из C #:

using System;
using System.Runtime.InteropServices;namespace wrappertest
{
class Program
{
[DllImport("matrixwrapper.dll")]
unsafe public static extern void* Make(int m,int n);

[DllImport("matrixwrapper.dll")]
unsafe public static extern void setData(void* mp,int m, int n,double d);

[DllImport("matrixwrapper.dll")]
unsafe public static extern double getData(void* mp,int m, int n);

static unsafe void Main(string[] args)
{
void* p = Make(10, 10);
setData(p,10,1,10);
Console.WriteLine(getData(p,10,1));
}
}
}

Но когда я пытаюсь запустить методы DLL C ++ из C #, я получаю следующую ошибку

1 // Попытка чтения или записи в защищенную память. Это часто указывает на то, что другая память повреждена при выполнении кода C # в x64.

2 // Была предпринята попытка загрузить программу с неверным форматом при запуске в x86 Active / x86 или на платформе AnyCPU.

Вопросы:

1 // Что не так в приведенном выше коде?

2 // Учитывая, что моей конечной целью является создание двумерного динамического массива в C ++ и чтение / запись данных в массиве, таких как один двойной символ ** в приведенном выше файле matrixheader.h из C #? Есть ли другой способ реализации Это ?

2

Решение

Давайте сначала получим простую вещь:

Была предпринята попытка загрузить программу с неверным форматом при запуске в x86 Active / x86 или на платформе AnyCPU.

Это просто означает, что у вас несоответствие платформы. Вы либо пытаетесь загрузить dll x86 C ++ в среде выполнения x64 .NET, либо наоборот.

Следующая ошибка — настоящая проблема:

Попытка чтения или записи защищенной памяти. Это часто указывает на то, что другая память повреждена при запуске кода C # в x64.

Этого следовало ожидать, потому что ваш Make Функция создает объект в стеке, а затем возвращает указатель на него. К тому времени, когда вы читаете этот объект обратно, содержимое стека изменилось (стек используется повторно), и mat указатель указывает куда-то еще, скорее всего, в нераспределенную память.

пожалуйста увидеть этот ответ где я углубляюсь в подробности об этой проблеме (это C #, но это та же проблема).

Вы должны выделить динамическую память, чтобы решить вашу проблему. Вы можете попробовать:

extern "C" __declspec(dllexport) void* Make(int m,int n)
{
M* o = new M(m,n);
return o;
}

И, конечно же, вам придется создать еще один метод для сопоставления delete если вы не хотите утечки памяти.

Кроме того, как Mgetz указывает в комментариях, у вас есть утечка памяти в M сам класс. delete[] mat; вызов в деструкторе не освободит каждый выделенный кусок памяти. Ты звонишь new в конструкторе m + 1 раз это означает, что вы должны позвонить delete[] m + 1 раз также в деструкторе, один раз для каждого new, Вы, вероятно, должны сохранить m а также n как поля в вашем классе (по крайней мере, m обязательно знать, сколько звонков delete[] ты должен сделать).

Гораздо лучшим решением было бы использование одного массива вместо зубчатых массивов. Вы рассчитываете индекс i, j в этом массиве как i * m + j, Вы также можете использовать std::vector или просто сделать это в C #:

public class M
{
private double[] _items;
private int _m;
private int _n;

public M(int m, int n)
{
_items = new double[m * n];
_m = m;
_n = n;
}

public this[int i, int j]
{
// Here, you should perform a bounds check on i and j against _m and _n
get { return _items[i * _m + j]; }
set { _items[i * _m + j] = value; }
}
}
1

Другие решения


По вопросам рекламы [email protected]