Span<T>: いろんなところ参照• Managedヒープも、Nativeヒープも、スタックも参照できるSpan<byte>span = new byte[N];Span<byte> span = stackalloc byte[N];var p = Marshal.AllocHGlobal(N);Span<byte> span = new Span<byte>((byte*)p, N);普通の配列 = Managedヒープstackalloc = スタックP/Invokeやunsafe = Nativeヒープ同じ型で参照できる= 同じロジックで扱える
36.
C# 7.2: Span安全ルール•スタック(ローカル変数)の参照を外に返してはいけないref int Ok(ref int x){return ref x;}ref int Ng(){int x;return ref x;}Span<int> Ok(Span<int> x){return x;}Span<int> Ng(){Span<int> x = stackalloc int[1];return x;}ref安全ルール(C# 7.0) Span<T>※安全ルール(C# 7.2)ローカル変数(メソッドを抜けると消える)消えるものの参照(返そうとするとエラー)※ 正確にはSpan<T>専用ではなくて、ref構造体に対して掛かる制限
37.
C# 7.2: 安全なstackalloc•例: 頻出数字の検索static int MostFrequentDigit(string s){var digits = new int[10];foreach (var c in s){var d = c - '0';if ((uint)d < 10) ++digits[d];}var max = 0;for (int i = 1; i < 10; i++)if (digits[max] < digits[i]) max = i;return max;}0~9の文字の頻度をカウントするための一時バッファー配列のせいでヒープ確保(あんまり好ましくない)
38.
C# 7.2: 安全なstackalloc•例: 頻出数字の検索static int MostFrequentDigit(string s){Span<int> digits = stackalloc int[10];foreach (var c in s){var d = c - '0';if ((uint)d < 10) ++digits[d];}var max = 0;for (int i = 1; i < 10; i++)if (digits[max] < digits[i]) max = i;return max;}一時バッファーをnewからstackallocに変更ヒープ確保がなくなる(速い)unsafe不要実際、安全• 範囲チェックあり• 外に返せないルールあり