2011-02-02 19 views
0

まず、私たちの環境に関する基本情報:Win7-x64では32ビットをターゲットとしたc#.net 4.0を使用しています。Cで配列の途中にポインタを移動する方法

事前に割り当てられた大型配列があります。ある関数では、この配列の任意の点へのポインタを返すので、呼び出し関数はどこに書き込むべきかを知ることができます。例:

class SomeClass { 
    void function_that_uses_the_array() { 
     Byte [] whereToWrite = getEmptyPtrLocation(1200); 
     Array.Copy(sourceArray, whereToWrite, ...); 
    } 
} 

class DataProvider { 
    int MAX_SIZE = 1024*1024*64; 
    Byte [] dataArray = new Byte[MAX_SIZE]; 
    int emptyPtr=0; 
    Byte[] getEmptyPtrLocation(int requestedBytes) { 
     int ref = emptyPtr; 
     emptyPtr += requestedBytes; 
     return dataArray[ref]; 
    } 
} 

は基本的に、我々は、このメモリブロックのメモリの大きな塊、及び予備任意の長さの部分を事前に割り当てると、他のいくつかのクラス/関数は、メモリの一部を使用するようにしたいです。

上記の例では、getEmptyPtrLocation関数が正しくありません。 Byte []を返すものとして宣言されていますが、1バイトの値を返そうとしています。アンマネージコードに行かなくても

おかげ

+3

を使用することができますか? – Femaref

答えて

4

他の人が言っているように、C#でこれを行うことはできません - 一般にのようにするべきではありません。システムでの作業 -

など

ガベージコレクタを活用し、あなたが彼らの割り当てられたスロットをオーバーランしないようにクライアントを信頼することができますが、 似た何かをしたい場合や、あなたのメソッドの戻り ArraySegment<byte>を作ることができる、と述べました byte[]の代わりに。それは「配列の一部」を表すでしょう。明らかに.NETのメソッドのほとんどは ArraySegment<T>を使用していませんが、 の場合は、使用したいいくつかのより一般的な操作のターゲットとして使用する可能性があります。

+0

私はガベージコレクタを聞いた議論は数回行われますが、これまでのテストでは、事前割り振りが役立つことが示されています。アプリケーションの特性に大きく依存することはありますか?私たちのアプリケーションでは、毎秒約250回のメモリの2K〜128K(毎回異なるサイズ)の間で割り当て/割り当てを解除する必要があります。 – SomethingBetter

+0

@SomethingBetter:さまざまなサイズの配列を事前に配分することを検討しましたが、発信者は1つの大きな配列内のサブアレイではなく、異なるサイズのバッファを取得できますか? –

+0

多分、長さが大きく異なり、断片化/空きスペースがたくさんあります。実際、私の根本的な問題の1つは、サードパーティライブラリを使用しているため、データを任意の位置に配列として読み取ることができないということです。私は別の質問としてここに投稿しました:[http://stackoverflow.com/questions/4895799/pinvoke-pointers-and-array-copy](http://stackoverflow.com/questions/4895799/pinvoke-pointers-配列コピー)。私はどんな洞察にも感謝します。 --thanks – SomethingBetter

2

を、あなたはあなたがすることができるすべては、あなたがデータを入力したい配列のインデックスを返すで、C#で配列の中央へのポインタを返すことはできません。

3

これはC#ではなくC + +です - あなたは本当にここでガベージコレクタに反対しています。メモリの割り当ては、C#で一般的に非常に高速です。また、C++で事前割り振りする他の主な理由の1つであるメモリの断片化に悩まされることもありません。

あなたはまだそれをやりたいと思っていますが、私はちょうど配列インデックスと長さを使用するので、Array.Copyを使ってその位置に書き込むことができます。

編集:

他の人が指摘しているArraySegment<T>は、より良いあなたのニーズに合ったよう:それは、配列のちょうど彼のスライスに消費者を制限し、それがコンテンツを更新する前に、別の配列を割り当てる必要はありません。元の配列(ArraySegmentで表される)に格納されます。

+0

感情に同意する(これはしないでください)、Array.Copyの使用には同意しません。新しいメモリが割り当てられ、配列のサブセットは返されません。 MSDNから:http://msdn.microsoft.com/en-us/library/k4yx47a1.aspx –

+0

@Chris:Agreed - Array.Copyは、それを使用してターゲットバッファにコピーする前に独自のバッファを割り当てる必要がありますまた、それらは完全な配列にアクセスすることができます - そうです、 'ArraySegment'が望ましいでしょう。 – BrokenGlass

+1

@jon、@Chris、@BrokenGlass:ArraySegment の情報をありがとう、このクラスについて初めて聞いた。しかし、それは非常に有用ではないようです。あなたは[]でArraySegmentのインデックスを作成することはできません。また、それを反復処理することもできません。どうやら、ArraySegment.Arrayフィールドにアクセスしてから、[id]を元の配列インデックスとする[]でインデックスする必要があります。ここに良い[リンク](http://weblogs.asp.net/wim/archive/2006/06/14/ArraySegment-Structure---what-were-they-thinking_3F00_.aspx) – SomethingBetter

1

にする必要がある場合は、ArraySegment(Jon Skeetが指摘したように)を返すか、Streamsを使用するかを選択できます。 thisコンストラクタを使用して、配列のサブセットであるMemoryStreamを返すことができます。ただし、オフセット操作ではなく、すべてのメモリー読み取りと書き込みをストリーム操作として処理する必要があります。

1

これはかなり古い投稿ですが、私は簡単な解決策があります。私はこの質問に「あなたはしてはいけない」のような答えがたくさんあることがわかります。何かをする方法があれば、それを使わないでください。

しかし、それはさておき、あなたはなぜあなたはそれをやっている、次の

int[] array = new int[1337]; 
position = 69; 
void* pointer = (void*)Marshal.UnsafeAddrOfPinnedArrayElement(array, position); 
関連する問題