私はこれを検索しようとしましたが、何も見つかりませんでしたが、int[] をポインターとしてネイティブ DLL 関数に渡すと、DLL がポインターへの参照を維持できる危険性がまだありません。 「固定」ブロックが終了した後に再度アクセスしますか? GC がアレイを移動した場合、メモリ アクセス エラーが発生しませんか? もしそうなら、どうやってこれを回避しますか?それとも、これはありそうもないシナリオですか?
2 に答える
更新: この質問は、2012 年 12 月 11 日の私のブログの主題でした。素晴らしい質問をありがとう!
これを検索しようとしましたが、何も見つかりませんでした
言語について質問がある場合は、言語仕様を読むことを検討してください。
int[] をポインターとしてネイティブ DLL 関数に渡す場合、DLL がポインターへの参照を維持し、「固定」ブロックが終了した後に再度アクセスしようとする危険性はまだありませんか?
うん。言語仕様には次のように記載されています。
固定ステートメントによって作成されたポインターが、それらのステートメントの実行を超えて存続しないようにすることは、プログラマーの責任です。たとえば、fixed ステートメントによって作成されたポインターが外部 API に渡される場合、API がこれらのポインターのメモリを保持しないようにするのは、プログラマーの責任です。
GC がアレイを移動した場合、メモリ アクセス エラーが発生しませんか?
はい!
もしそうなら、どうやってこれを回避しますか?
あなたはそうしない。言語仕様に記載されているように、決してそれを行う必要はありません。あなたはそれを決してしないので、それを回避する方法を見つける必要はありません. それはむしろ、「どうすれば致命的な自分自身を撃ったことから回復することができますか?」と尋ねるようなものです。そうではありません -- 死にたくないのであれば、「そもそも自分を撃ってはいけません」というのが良いルールです。
それとも、これはありそうもないシナリオですか?
マネージ コードの規則に違反する DLL を呼び出す C# プログラムを作成する可能性はありますか? わからない!あなたは私に言います-それはあなたが誘惑されるかもしれないとあなたが思うようなことですか?
これは、問題を解決するために作成したクラスです。AllocHGlobal を使用して unmanaged にメモリ空間を作成し、その空間へのポインターをラップします。残念ながら、このジェネリックを作成してもうまくいかないようです。メソッド内でfrom からvoid*
toにキャストする方法が見つからないからです。T
this[int i]
unsafe sealed class FixedFloatArray : IDisposable {
readonly float* _floats;
internal FixedFloatArray(int size) {
_floats = (float*)Marshal.AllocHGlobal(sizeof(float) * size);
}
internal FixedFloatArray(float[] floats) {
_floats = (float*)Marshal.AllocHGlobal(sizeof(float) * floats.Length);
Marshal.Copy(floats, 0, (IntPtr)_floats, floats.Length);
}
internal float this[int i] {
get { return _floats[i]; }
set { _floats[i] = value; }
}
internal void CopyFrom(float[] source, int sourceIndex, int destinationIndex, int length) {
var memoryOffset = (int)_floats + destinationIndex * sizeof(float);
Marshal.Copy(source, sourceIndex, (IntPtr)memoryOffset, length);
}
internal void CopyTo(int sourceIndex, float[] destination, int destinationIndex, int length) {
var memoryOffset = (int)_floats + sourceIndex * sizeof(float);
Marshal.Copy((IntPtr)memoryOffset, destination, destinationIndex, length);
}
public static implicit operator IntPtr(FixedFloatArray ffa) {
return (IntPtr)ffa._floats;
}
public void Dispose() {
Marshal.FreeHGlobal((IntPtr)_floats);
}
}