Как известно в C# можно инициализировать массивы в месте их объявления указывая значения в фигурных скобках. Я так всегда и делал, но тут решил посмотреть во что-же это превращается в IL. Оказалось что такой вот код:
static void Main()
{
var arr = new[] { 1, 2 };
Console.WriteLine(arr); // если не использовать переменную arr где нибудь, то её оптимизирует компилятор
}
Вопрос зачем компилятор создает две ссылки numArray когда хватило бы и одной? Причём он генерирует такой код только если выполняешь инициализацию массива используя синтаксис фигурных скобок, во всех других случаях генерируется оптимальный код.
P/S — Оптимизация если что включена!
:)
Re: Странный код при использовании инициализатора массива
Здравствуйте, Cynic, Вы писали:
C>Вопрос зачем компилятор создает две ссылки numArray когда хватило бы и одной? Причём он генерирует такой код только если выполняешь инициализацию массива используя синтаксис фигурных скобок, во всех других случаях генерируется оптимальный код.
Мож какая временная переменная Во всяком случае похоже на это.
Кодом людям нужно помогать!
Re: Странный код при использовании инициализатора массива
Здравствуйте, Cynic, Вы писали:
C>Вопрос зачем компилятор создает две ссылки numArray когда хватило бы и одной? Причём он генерирует такой код только если выполняешь инициализацию массива используя синтаксис фигурных скобок, во всех других случаях генерируется оптимальный код.
Критерий оптимальности сомнительный. ЕМНИП, там идея в том, что массив надо присвоить полностью инициализированным. Поэтому операции заполнения массива делаются с доп. переменной, значение которой потом перемещается в фактическую.
Re[2]: Странный код при использовании инициализатора массива
Здравствуйте, MxMsk, Вы писали:
C>>Вопрос зачем компилятор создает две ссылки numArray когда хватило бы и одной? Причём он генерирует такой код только если выполняешь инициализацию массива используя синтаксис фигурных скобок, во всех других случаях генерируется оптимальный код. MM>Критерий оптимальности сомнительный. ЕМНИП, там идея в том, что массив надо присвоить полностью инициализированным. Поэтому операции заполнения массива делаются с доп. переменной, значение которой потом перемещается в фактическую.
Для локальной переменной это неважно, т.к. кода, который бы мог пронаблюдать её недоинциализированной, не существует.
Скорее всего, compiler team просто пошла по пути наименьшего сопротивления, всегда порождая временную переменную для инициализации.
Это важно для тех случаев, когда финальный результат присваивается не в локальную переменную, а в object member, который может быть неожиданно прочитан из другого потока.
Уйдемте отсюда, Румата! У вас слишком богатые погреба.
Re: Странный код при использовании инициализатора массива
Здравствуйте, Cynic, Вы писали:
C>Вопрос зачем компилятор создает две ссылки numArray когда хватило бы и одной?
Отладочная сборка. В релизной вообще .locals не будет.
Здравствуйте, Sinclair, Вы писали:
S>Для локальной переменной это неважно, т.к. кода, который бы мог пронаблюдать её недоинциализированной, не существует. S>Скорее всего, compiler team просто пошла по пути наименьшего сопротивления, всегда порождая временную переменную для инициализации. S>Это важно для тех случаев, когда финальный результат присваивается не в локальную переменную, а в object member, который может быть неожиданно прочитан из другого потока.
Понятное дело. А я только про идею написал.
Re[3]: Странный код при использовании инициализатора массива
Здравствуйте, Cynic, Вы писали:
C>Вопрос зачем компилятор создает две ссылки numArray когда хватило бы и одной? Причём он генерирует такой код только если выполняешь инициализацию массива используя синтаксис фигурных скобок, во всех других случаях генерируется оптимальный код.
Потому что инициализатор работает так: (1) сначала создаётся массив, (2) потом инициализируются его элементы, (3) потом ссылка на массив присваивается локальной переменной. До шага (3) ты можешь использовать эту локальную переменную для других целей, если тебе вздумается, и это никак не должно повлиять на результат инициализации. Как же можно её использовать, если она ещё не проинициализирована? Очень проcто: в инициализаторах массива могут быть произвольные выражения, которые могут присваивать что-то этой переменной, передавать её как ref или out параметр в какие-то методы и т.д. Например:
using System;
class Program
{
static void Main()
{
int[] x = { 1, Foo(out x), Bar(x) };
Console.WriteLine();
foreach (var e in x)
{
Console.Write(e);
}
Console.WriteLine();
}
static int Foo(out int[] x)
{
x = new[] { 4, 5 };
return 2;
}
static int Bar(int[] x)
{
foreach (var e in x)
{
Console.Write(e);
}
return 3;
}
}
Результат:
45
123
Пара замечаний:
* этот трюк не пройдёт, если тип переменной объявлен как var.
* компилятор мог бы заметить что мы не пытаемся делать ничего подобного и всё-таки оптимизировать эту переменную.
Компилятор это и делает, если в инициализаторе достаточно большое количество элементов и все они константы. Почему же он не делает этого в данном случае? Потому что компилятор не может делать всех возможных оптимизаций. Все они требуют ресурсов (дизайн, разработка, тестирование), и в некоторых случаях потенциальный выигрыш не оправдывает этих вложений, и ресурсы лучше потратить на что-то другое (новые фичи, баг-фиксинг). Кроме того, с некоторыми оптимизациями лучше справляется JIT.