Здравствуйте, Sinclair, Вы писали:
_>>Ну я то писал про C++. Забавно, что в C# ситуация обратная. Кстати, а в какой код транслируется range for в C#? )
S>В С# range нету. Вместо них — Span<T>.
Эм, я имел в виду foreach. )
S>Он прекрасен тем, что позволяет сослаться на более-менее любую память. Наиболее популярный сценарий — кусок массива.
S>Так вот — он решает проблемы с детектированием границ:
S>public static void foo(int[] arr)
S>{
S> int64 sum = 0;
S> for(int i=0; i<arr.Count; i++)
S> sum+=arr[i]; // проверка устранена
S> int64 sum = 0;
S> for(int i=0; i<arr.Count-1; i++)
S> sum+=arr[i]; // проверка не устранена!
S> var subarray = new Span<int>(arr, 0, arr.Count-1); // один раз проверили границы здесь
S> int64 sum = 0;
S> for(int i=0; i<subarray.Count; i++)
S> sum+=subarray[i]; // проверка устранена!
S>}
S>
Да, выглядит не плохо, хотя было бы красивее иметь что-то вроде foreach для Span.
_>>Не значит. Если в теле цикла есть другой (модифицирующий) вызов a. Вот в случае константного a всё однозначно. А когда константности нет, то компилятор должен сам отслеживать и не всегда у него это удаётся верно.
S>Зависит от толщины тела. В простых случаях компилятор просто видит, что модифицирующих вызовов нет — всё, константность нам монопенисуальна.
Ну я так и писал, что константность не обязательна — это скорее гарантия. А так, компилятор смотрит сам и почти всегда правильно. Но почти... Ошибки естественно всегда в сторону перестраховки.
S>Кстати, что будет, если a — константен, но внутри цикла мы имеем const_cast и принудительную модификацию? Всё падает, или компилятор видит палево и отменяет оптимизацию?
Контроль работает где-то на уровне потенциального доступа к указателям. Так что если есть шанс модифицирующего доступа, то оптимизации не будет.