No se puede ordenar una variedad de elementos de C ++ a C # en Unity

Estoy tratando de pasar una serie destructs de C ++ a un script de Unity en C #. Cuando uso el código en producción, el tamaño de la matriz variará enormemente, por lo que efectivamente necesito pasar una matriz de longitud desconocida.

Mi idea inteligente era almacenar la matriz en el montón y pasar una referencia a esa matriz a Unity. He encontrado publicaciones de StackOverflow sobre cómo hacer eso. Pero luego, Unity se queja de que una referencia es nula.

Aquí hay parte de mi código C ++:

extern "C" struct S; // Not currently used.

struct S {
  int i;
  float f;
};

extern "C" bool helloWorld(S ** a, int * i);

S * s;

bool helloWorld(S ** a, int * i) {
  s = new S[4];
  for (int j = 0; j < 4; j++) {
    s[j].i = j;           // Fill in placeholder
    s[j].f = (float) j;   // data for now.
  }
  *a = s; // I don't know if this works.
  *i = 4; // Works.
  return true;
}

Intenté esto conints en lugar destructsy funcionó.

Ahora, mi código C # es:

[StructLayout(LayoutKind.Sequential),Serializable]
public struct S {
  int i;
  float f;
};

void Start() {
  IntPtr ptrNativeData = IntPtr.Zero;
  int itemsLength = 0;

  bool success = helloWorld(ref ptrNativeData, ref itemsLength);
  if (!success) {
    return;
  }

  S[] SArray = new S[itemsLength];  // Where the final data will be stored.
  IntPtr[] SPointers = new IntPtr[itemsLength];

  Debug.Log("Length: " + itemsLength); // Works!
  Marshal.Copy(ptrNativeData, SPointers, 0, itemsLength); // Seems not to work.

  for (int i = 0; i < itemsLength; i++) {
    Debug.Log("Pointer: " + SPointers[i]); // SPointers[0] prints 0.
    Marshal.PtrToStructure(SPointers[i], SArray[i]); // Crashes here. Boom.
  }
}

[DllImport("TestUnity")]
private static extern bool helloWorld(ref IntPtr ptrResultVerts,
    ref int resultVertLength);

losMarshal.PtrToStructure La instrucción dice que el argumento SPointers [i] es nulo. Verifiqué con el comando Debug.Log y, de hecho, parece nulo: se imprime como 0.

Pero probé algo similar con una serie deints antes y eso funcionó. Lo que no estoy seguro es: ¿es mi problema en C ++ o en C #? ¿No estoy pasando la información correcta o estoy procesando la información correcta de manera incorrecta?

Solución 1

Esta fue la primera solución que se me ocurrió principalmente por mi cuenta. La segunda solución es mejor.

Totalmente gracias a Alex Skalozub, lo descubrí. Un nivel de indirección del puntero se abstrae durante la clasificación. Entonces, mi código C ++ contiene:

S ** s; // Not a pointer to Ss, but a pointer to pointers to Ss.

bool helloWorld(S *** a, int * i) { // Pass a triple pointer.
  s = new S * [4]; // Create array of pointers.
  for (int j = 0; j < 4; j++) {
    s[j] = new S; // Actually create each object.
    s[j]->i = j;
    s[j]->f = (float) j;
  }
  *a = s;
  *i = 4;
  return true;
}

Y mi código C # contiene:

for (int i = 0; i < itemsLength; i++) {
  Debug.Log("Pointer: " + SPointers[i]);
  SArray[i] = (S) Marshal.PtrToStructure(SPointers[i], typeof(S));
}

¡Y eso es! Todos los datos se transfieren.

Ahora esto me deja con un problema de administración de memoria:cada objeto creado en el código C ++ tendrá que ser liberado. Soy consciente de eso y me ocuparé de eso a continuación.

Solución 2

Ver la respuesta marcada. La respuesta de Alex es mucho mejor, ya que hace mucho menos uso de punteros innecesarios. Usé más punteros porque acababa de descubrir cómo usarlos en C #.

Respuestas a la pregunta(2)

Su respuesta a la pregunta