432
Глава.16 .Массивы
небезопасный доступ к массивам
и массивы фиксированного размера
Небезопасный доступ к массиву является крайне мощным средством, так как именно
такой доступ дает возможность работать:
с элементами управляемого массива, расположенными в куче (как показано
в предыдущем разделе);
с элементами массива, расположенными в неуправляемой куче (пример
SecureString
из главы 14 демонстрирует небезопасный метод доступа к мас-
сиву, возвращаемому методом
SecureStringToCoTaskMemUnicode
класса
System.
Runtime.InteropServices.Marshal
);
с элементами массива, расположенными в стеке потока.
Если производительность для вас критична, управляемый массив можно вместо
кучи разместить в стеке потока. Для этого вам потребуется инструкция
stackalloc
языка C# (ее принцип действия напоминает функцию
alloca
языка C). Она позво-
ляет создавать одномерные массивы элементов значимого типа с нулевой нижней
границей. При этом значимый тип не должен содержать никаких полей ссылочного
типа. По сути, вы выделяете блок памяти, с которым можно работать при помощи не-
безопасных указателей, поэтому адрес этого буфера нельзя передавать большинству
FCL-методов. Выделенная в стеке память (массив) автоматически освобождается
после завершения метода. Именно за счет этого и достигается выигрыш в произво-
дительности. При этом для компилятора C# должен быть задан параметр
/unsafe
.
Метод
StackallocDemo
демонстрирует пример использования инструкции
stackalloc
:
using System;
public static class Program {
public static void Main() {
StackallocDemo();
InlineArrayDemo();
}
private static void StackallocDemo() {
unsafe {
const Int32 width = 20;
Char* pc = stackalloc Char[width]; // В стеке выделяется
// память под массив
String s = "Jeffrey Richter"; // 15 символов
for (Int32 index = 0; index < width; index++) {
pc[width - index - 1] =
(index < s.Length) ? s[index] : '.';
}
433
Небезопасный.доступ.к.массивам.и.массивы.фиксированного.размера
// Следующая инструкция выводит на экран ".....rethciR yerffeJ"
Console.WriteLine(new String(pc, 0, width));
}
}
private static void InlineArrayDemo() {
unsafe {
CharArray ca; // Память под массив выделяется в стеке
Int32 widthInBytes = sizeof(CharArray);
Int32 width = widthInBytes / 2;
String s = "Jeffrey Richter"; // 15 символов
for (Int32 index = 0; index < width; index++) {
ca.Characters[width - index - 1] =
(index < s.Length) ? s[index] : '.';
}
// Следующая инструкция выводит на экран ".....rethciR yerffeJ"
Console.WriteLine(new String(ca.Characters, 0, width));
}
}
}
internal unsafe struct CharArray {
// Этот массив встраивается в структуру
public fixed Char Characters[20];
}
Так как массивы относятся к ссылочным типам, поле массива, определенное
в структуре, содержит указатель или ссылку на этот массив; при этом сам он рас-
полагается вне памяти структуры. Впрочем, существует возможность встроить
массив непосредственно в структуру. Вы это видели в показанном коде на примере
структуры
CharArray
. При этом должны соблюдаться следующие условия:
тип должен быть структурой (значимым типом), встраивать массивы в класс
(ссылочный тип) нельзя;
поле или структура, в которой оно определено, должно быть помечено моди-
фикатором
unsafe
;
поле массива должен быть помечено модификатором
fixed
;
массив должен быть одномерным и с нулевой нижней границей;
элементы массива могут принадлежать только к типам:
Boolean
,
Char
,
SByte
,
Byte
,
Int32
,
UInt32
,
Int64
,
UInt64
,
Single
и
Double
.
Встроенные массивы обычно применяются в сценариях, работающих с не-
безопасным кодом, в котором неуправляемая структура данных также содержит
встроенный массив. Впрочем, никто не запрещает использовать их и в других слу-
чаях, например, как показано ранее в методе
InlineArrayDemo
, который по-своему
решает ту же задачу, что и метод
StackallocDemo
.
Do'stlaringiz bilan baham: |