2009-03-15 26 views
43

Cada vez que se asigna una nueva matriz en C# coninicialización de la matriz directa con un valor constante

new T[length] 

las entradas de la matriz se establece en el valor por defecto de T. Es decir null para el caso de que T es un tipo de referencia o el resultado del constructor predeterminado de T, si T es un tipo de valor.

En mi caso quiero inicializar una matriz Int32 con el valor -1:

var myArray = new int[100]; 
for (int i=0; i<myArray.Length; i++) { myArray[i] = -1; } 

Así que después de que la memoria se reserva para la matriz, el CLR bucles sobre la memoria recién asignada y establece que todas las entradas default (int) = 0. Después de eso, mi código establece todas las entradas en -1.

Eso hace que la inicialización sea redundante. ¿El JIT detecta esto y descuida la inicialización a 0 y, de no ser así, hay una forma de inicializar directamente una parte de la memoria con un valor personalizado?

Con referencia a C# Array initialization - with non-default value, usar Enumerable.Repeat(value, length).ToArray() no es una opción, porque Enumerable.ToArray asigna una nueva matriz y luego copia los valores a la misma.

+1

Si usted tiene byte array, luego [P/Invoke podría ayudar] (http://stackoverflow.com/a/19060558/380331). Pero si el tamaño del elemento de matriz es mayor que el byte (como en su caso), este método no será de ayuda. –

Respuesta

32

No es redundante.

Supongamos que se produce una excepción durante el ciclo de inicialización. Si el CLR no borró la memoria primero, es posible que pueda "ver" la memoria original no inicializada, lo cual es una muy mala idea, especialmente desde el punto de vista de la seguridad. Es por eso que CLR garantiza que cualquier memoria recientemente asignada se borrará a un patrón de 0 bits.

El mismo argumento vale para los campos en un objeto, por cierto.

Supongo que en ambos casos el CLR podría verificar que no va a hacer que la matriz sea visible en otro lugar antes de finalizar la inicialización, pero es una verificación complicada para evitar un simple "borrado de esta área de memoria".

+0

No veo dónde se podría lanzar una excepción. El JIT es lo suficientemente inteligente como para desactivar las comprobaciones de rango en la matriz dentro del bucle, por lo que también podría detectar que no se puede producir ninguna excepción. – Rauhotz

+6

@Rauhotz ThreadAbortException se puede lanzar en cualquier momento. – JaredPar

+0

Bien, ese es un punto – Rauhotz

3

Dudo mucho que el JIT optimice el conjunto predeterminado para este escenario. La razón es que esta sería una diferencia observable. Considere el siguiente escenario levemente alterado.

obj.myArray = new int[100]; 
for (int i=0; i<myArray.Length; i++) { obj.myArray[i] = -1; } 

Es completamente posible que el bucle arroje. Al menos, probablemente no sea posible para el JIT demostrar que no. Si lo hizo tirar y el CLR no inicializó por defecto la memoria, el resultado sería observable si todavía tuviera una referencia a obj.

+0

Limite el problema a las variables locales. – Rauhotz

+0

@Rauhotz, en ese punto debe comenzar a preguntarse si la optimización vale la pena o no. Ahora lo has limitado a un escenario muy restringido. – JaredPar

10

Si usted compra en Arrays considered somewhat harmful, entonces su pregunta sería discutible como se escribirían:

var myArray = new List<int>(Enumerable.Repeat(-1, 100)); 
+4

Probablemente valga la pena mencionar que su enlace es al blog de Eric Lippert, que argumenta que las matrices son malas noticias porque, en muchos casos, "la persona que llama está solicitando valores. El destinatario realiza la solicitud devolviendo las variables". Lippert luego argumenta que, debido a restricciones físicas que hacen que los procesadores sean más rápidos, "Vamos a necesitar lenguajes de programación que permitan a simples mortales escribir código que sea paralelizable a matrices múltiples [y que] matrices ... trabajen en contra de este objetivo. " Es una gran lectura, apenas relacionada tangencialmente con esta pregunta. ; ^) – ruffin

26

Similar a la respuesta de Dan, pero sin la necesidad de utilizar las colecciones:

int[] myArray = Enumerable.Repeat(-1, 100).ToArray(); 
Cuestiones relacionadas