2009-03-15 8 views
43

Chaque fois que vous allouez un nouveau tableau en C# avecinitialisation du tableau direct avec une valeur constante

new T[length] 

les entrées du tableau sont définis par défaut de T. C'est null pour le cas où T est un type de référence ou le résultat du constructeur par défaut de T, si T est un type de valeur.

Dans mon cas, je veux initialiser un tableau Int32 avec la valeur -1:

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

Ainsi, après la mémoire est réservée au tableau, les boucles CLR sur la mémoire nouvellement allouée et définit toutes les entrées default (int) = 0. Après cela, mon code définit toutes les entrées à -1.

Cela rend l'initialisation redondante. Est-ce que le JIT détecte ceci et néglige l'initialisation à 0 et sinon, est-il possible d'initialiser directement une partie de la mémoire avec une valeur personnalisée? En se référant à C# Array initialization - with non-default value, l'utilisation de Enumerable.Repeat(value, length).ToArray() n'est pas une option, car Enumerable.ToArray alloue un nouveau tableau et lui copie les valeurs par la suite.

+1

Si vous avez octet array, alors [P/Invoke pourrait aider] (http://stackoverflow.com/a/19060558/380331). Mais si la taille de l'élément de tableau est plus grande que l'octet (comme dans votre cas) - cette méthode n'aidera pas. –

Répondre

32

Ce n'est pas redondant.

Supposons qu'une exception soit levée pendant votre boucle d'initialisation. Si le CLR n'a pas d'abord effacé la mémoire, vous pourrez peut-être "voir" la mémoire non initialisée d'origine, ce qui est une très mauvaise idée, en particulier du point de vue de la sécurité. C'est pourquoi le CLR garantit que toute nouvelle mémoire allouée est effacée à un motif de 0 bit.

Le même argument est valable pour les champs d'un objet. Je suppose que dans les deux cas le CLR pourrait vérifier que vous n'alliez pas rendre le tableau visible ailleurs avant de finir l'initialisation, mais c'est une vérification compliquée pour éviter une simple "effacement de cette zone de mémoire".

+0

Je ne vois pas où une exception pourrait être levée. Le JIT est assez intelligent pour désactiver les vérifications de plage sur la baie dans la boucle, de sorte qu'il peut également détecter qu'aucune exception ne peut se produire. – Rauhotz

+6

@Rauhotz ThreadAbortException peut être lancé à tout moment. – JaredPar

+0

OK, c'est un point – Rauhotz

3

Je doute fortement que le JIT optimise l'ensemble par défaut pour ce scénario. La raison en est que ce serait une différence observable. Considérez le scénario légèrement modifié suivant.

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

Il est tout à fait possible de lancer la boucle. Au moins, il n'est probablement pas possible pour le JIT de prouver que ce n'est pas le cas. Si elle a été lancée et que le CLR n'a pas initialisé la mémoire par défaut, le résultat serait observable si vous aviez toujours une référence à obj.

+0

Limitez le problème aux variables locales. – Rauhotz

+0

@Rauhotz, à ce stade, vous devez commencer à se demander si l'optimisation en vaut la peine. Vous l'avez maintenant limité à un scénario très contraint. – JaredPar

10

Si vous achetez dans Arrays considered somewhat harmful, votre question serait sans objet que vous écrivez:

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

Il est probablement intéressant de mentionner son lien vers le blog d'Eric Lippert, qui démontre que les tableaux sont de mauvaises nouvelles car, dans de nombreux cas, "l'appelant demande des valeurs, l'appelé répond à la demande en lui rendant des variables". Lippert soutient ensuite que, en raison de contraintes physiques rendant les processeurs plus rapides, «nous allons avoir besoin de langages de programmation qui permettent aux simples mortels d'écrire du code parallélisable à plusieurs cœurs [et que] les tableaux ... travaillent fortement contre cet objectif. " C'est une excellente lecture, si elle est à peine liée de manière tangentielle à cette question. ^) – ruffin

26

similaires à la réponse de Dan, mais sans qu'il soit nécessaire d'utiliser des collections:

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