¿Por qué las matrices de memoria no son redimensionables?

No sé la longitud requerida de mi matriz antes de la ejecución de la función... ¿por qué técnicamente no puedo cambiar el tamaño de mi matriz de memoria?

¿Cuál es la forma común de solucionar este problema, si también lo enfrenta?

Podría hacer una matriz de almacenamiento y borrarla al final de la función, pero ¿se necesitaría más gasolina? También conozco el límite superior de la longitud requerida, por lo que podría asignar una matriz de memoria con el tamaño del límite superior, pero el 95% no se usaría la mayor parte del tiempo.

Para dejar en claro que estoy diseñando un mercado, hay n órdenes de compra y m de venta, quiero igualarlas, la matriz matchedOrders puede tener un tamaño máximo de (m, n).

Actualicé la respuesta con otro enfoque que podría funcionar para usted.

Respuestas (3)

tl; dr Tiene razón en que no es posible actualmente, pero no hay una razón fundamental por la que Solidity no pueda implementar la función en el futuro.

Los arreglos de tamaño completamente dinámico no encajan fácilmente con el modelo de memoria de EVM. Podría existir una matriz de tamaño arbitrario, pero tendría que estar más arriba en la memoria que todo lo demás para permitirle crecer hacia arriba de manera ilimitada. Entonces, por definición, solo podría tener uno de ellos y, en cualquier caso, es difícil para el compilador organizar esto en general.

En realidad, las matrices de tamaño dinámico son un lujo para nosotros, los tipos de la vieja escuela. C no los tiene por ejemplo. Debe reservar específicamente la memoria para la matriz que se usa malloc()en tiempo de ejecución.

Hay básicamente dos escenarios:

  1. Matrices de tamaño arbitrario que pueden crecer bajo demanda. Solidity probablemente podría implementarlos usando una estructura de lista enlazada/lista salteada internamente, pero esto no se ha hecho.

  2. Matrices de tamaño dinámico que se pueden crear sobre la marcha pero que mantienen el tamaño fijo una vez creadas. (Esto cumpliría con su requisito). No puedo ver ninguna razón en particular por la cual Solidity no pueda implementar esto y debería ser bastante fácil. Nuevamente, simplemente no se ha hecho Ver actualización a continuación . Por cierto, puede hacer esto en el lenguaje Ethereum LLL a través de la allocexpresión, por lo que no hay una limitación fundamental.

Los arreglos de almacenamiento son fundamentalmente diferentes de los arreglos de memoria y están indexados por un mecanismo clave=>valor, por lo que es mucho más fácil hacerlos dinámicos. Usar una matriz de almacenamiento y ponerlo a cero al salir es una idea interesante, pero solo recuperará aproximadamente la mitad del gas; cada elemento costará alrededor de 10000 de gas, lo cual es enorme.

En resumen, por ahora, tendrá que asignar al menos el tamaño máximo concebible requerido o encontrar un algoritmo que use un tamaño de memoria fijo. Probablemente tendrá que poner un límite ny , men cualquier caso, evitar entrar en un estado en el que su contrato se vuelve inejecutable debido a que necesita más gasolina que el límite de bloque vigente.


Actualizar

Resulta que el enfoque 2 anterior es posible en Solidity. Puede usar la siguiente sintaxis para crear una matriz de tamaño arbitrario sobre la marcha. No será redimensionable, pero debe cumplir con sus requisitos.

function bar (uint n, uint m) returns (uint) {
    uint maxnm = n < m ? m : n;
    uint[] memory a = new uint[](maxnm);
    return a[maxnm-1];
}

Por lo general, las matrices de memoria no se pueden aumentar en tamaño porque la región de memoria posterior a ellas puede haber sido asignada para otros valores.

Sin embargo, se pueden reducir de tamaño mediante el ensamblaje en línea. Por ejemplo, esta línea disminuirá el tamaño de la matriz testArrayde memoria en 1.

assembly { mstore(testArray, sub(mload(testArray), 1)) }

Esta función devolverá 122:

function test() public pure returns (uint256)
{
    uint256[] memory testArray = new uint256[](123);
    assembly { mstore(testArray, sub(mload(testArray), 1)) }
    return testArray.length;
}

Siempre debe asegurarse de que la longitud de la matriz no se desborde (vaya por debajo de 0). Además, esto solo funciona en matrices de memoria de tamaño dinámico como ... memory[], pero no en matrices de memoria de tamaño estático como... memory[10]

La matriz puede ir seguida de datos usados. Por lo tanto, una extensión del tamaño M a N podría significar: la asignación de un sled N bytes nuevo + copiar M bytes de datos a esa nueva ubicación.

Es probable que el aumento de tamaño esté prohibido porque las operaciones de lectura y escritura de memoria involucradas son potencialmente costosas, y el programador debe saber cuándo ocurren. Una llamada a una primitiva realloc(...) enmascararía esa información.