安全でないコードがアプリケーションの実行可能な代替手段である場合は、文字列の内容と長さを書き換えることができます。これにより、再利用可能な文字列のプールを事前に割り当てることができるため、ガベージ コレクションを回避できます。
AC# 文字列は、次のようにメモリに配置されます。
int Capacity;
int Length;
char FirstCharacter;
// remaining characters follow
文字データはヌルで終了し (アンマネージ C/C++ コードとの相互運用を容易にするため)、現在の長さと最大容量も格納されるため、厄介なバッファー オーバーランの問題を回避できます。
新しいメモリを割り当てずに既存の文字列に新しいコンテンツを挿入 する方法は次のとおりです。
static unsafe void RecycleString(string s, char[] newcontents)
{
// First, fix the string so the GC doesn't move it around on us, and get a pointer to the character data.
fixed (char* ps = s)
{
// We need an integer pointer as well, to check capacity and update length.
int* psi = (int*)ps;
int capacity = psi[-2];
// Don't overrun the buffer!
System.Diagnostics.Debug.Assert(capacity > newcontents.Length);
if (capacity > newcontents.Length)
{
for (int i = 0; i < newcontents.Length; ++i)
{
ps[i] = newcontents[i];
}
// Add null terminator and update length accordingly.
ps[newcontents.Length] = '\0';
psi[-1] = newcontents.Length;
}
}
}
それが整っていれば、同じ文字列を心ゆくまでリサイクルして再解析できます。以下に簡単な例を示します。
private static void ReusableStringTest()
{
char[] intFromWire = new char[] { '9', '0', '0', '0' };
char[] floatFromWire = new char[] { '3', '.', '1', '4', '1', '5' };
string reusableBuffer = new string('\0', 128);
RecycleString(reusableBuffer, intFromWire);
int i = Int32.Parse(reusableBuffer);
Console.WriteLine("Parsed integer {0}", i);
RecycleString(reusableBuffer, floatFromWire);
float f = Single.Parse(reusableBuffer);
Console.WriteLine("Parsed float {0}", f);
}
生成された出力は、期待どおりです。
解析済み整数 9000
解析済みフロート 3.1415
そして、安全でないコードがあなたを不安にさせるなら、私たちが C と C++ でプログラミングに費やしてきたすべての年月を思い出してください。