2009-03-15 3 views
43

Всякий раз, когда вы выделяете новый массив в C# сПрямая инициализация массива с постоянным значением

new T[length] 

элементы массива установлены по умолчанию Т. То есть null для случая, когда T является ссылочным типом или результат конструктора по умолчанию T, если T - тип значения.

В моем случае я хочу, чтобы инициализировать массив Int32 со значением -1:

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

Так после того, как память зарезервирована для массива, CLR перебирает вновь выделенную память и устанавливает все записи в default (int) = 0. После этого мой код устанавливает все записи в -1.

Это делает инициализацию избыточной. Описывает ли JIT это и игнорирует инициализацию до 0, а если нет, есть ли способ непосредственно инициализировать часть памяти с помощью специального значения?

Ссылаясь на C# Array initialization - with non-default value, использование Enumerable.Repeat(value, length).ToArray() не является опцией, так как Enumerable.ToArray выделяет новый массив и затем копирует значения в него.

+1

Если у вас есть байт массив, затем [P/Invoke может помочь] (http://stackoverflow.com/a/19060558/380331). Но если размер элемента массива больше байта (как в вашем случае) - этот метод не поможет. –

ответ

32

Это не избыточно.

Предположим, что во время цикла инициализации выбрано исключение. Если среда CLR не очистила память сначала, вы сможете «увидеть» оригинальную неинициализированную память, что является очень плохой идеей, особенно с точки зрения безопасности. Вот почему CLR гарантирует, что любая вновь выделенная память стирается до 0-битного шаблона.

Тот же аргумент имеет место для полей в объекте, между прочим.

Я полагаю, что в обоих случаях CLR может проверить, что вы не собираетесь делать массив видимым в другом месте до завершения инициализации, но это сложная проверка, чтобы избежать довольно простой «протрите эту область памяти».

+0

Я не вижу, где можно было бы исключить исключение. JIT достаточно интеллектуальна, чтобы отключить проверки диапазона массива в цикле, поэтому он также может обнаружить, что исключение не может произойти. – Rauhotz

+6

@Rauhotz ThreadAbortException может быть выбрано в любое время. – JaredPar

+0

ОК, это точка – Rauhotz

3

Я очень сомневаюсь, что JIT оптимизирует настройку по умолчанию для этого сценария. Причина в том, что это будет наблюдаемой разницей. Рассмотрим следующий слегка измененный сценарий.

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

Это вполне возможно для петли, которую нужно бросить. По крайней мере, для JIT, вероятно, невозможно доказать, что это не так. Если это было сделано, и среда CLR не инициализировала память по умолчанию, результат был бы наблюдаемым, если бы у вас все еще была ссылка на obj.

+0

Задайте проблему локальным переменным. – Rauhotz

+0

@Rauhotz, в этот момент вам нужно начинать спрашивать, стоит ли оптимизация. Теперь вы ограничили его очень ограниченным сценарием. – JaredPar

10

Если вы покупаете в Arrays considered somewhat harmful, то ваш вопрос будет спорный вопрос, как можно было бы написать:

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

Возможно, стоит упомянуть его ссылку на блог Эрика Липперта, в котором говорится о том, что массивы являются плохими новостями, потому что во многих случаях «вызывающий запрашивает значения. Ответчик выполняет запрос, передавая обратно переменные». Lippert тогда интересно утверждает, что из-за физических ограничений, создающих более быстрые процессоры: «Нам понадобятся языки программирования, которые позволяют простым смертным писать код, который можно распараллеливать с несколькими ядрами [и] массивами ... сильно работают против этой цели. " Это замечательное чтение, если оно едва касательно связано с этим вопросом. ; ^) – ruffin

26

Подобный ответ Дэна, но без необходимости использования коллекций:

int[] myArray = Enumerable.Repeat(-1, 100).ToArray(); 
Смежные вопросы