8

次のように C# で Swap ルーチンを作成しました。

static void Swap(ref int x, ref int y)
{
    int temp = x;
    x = y;
    y = temp;
}

次の C++ コードと同じことを行います。

void swap(int *d1, int *d2)
{
    int temp=*d1;
    *d1=*d2;
    *d2=temp;
}

コードを使用せずに C# のポインタのようなrefandoutキーワードですか?unsafe

4

7 に答える 7

10

それらはより制限されています。ポインタでは ++ と言えますが、refまたはではできませんout


編集コメントにいくつかの混乱があるため、明確にする必要があります。ここでのポイントは、ポインターの機能と比較することです。/と同じ操作を実行することはできませんptr++。つまり、メモリ内の隣接する場所をアドレス指定することはできません。と同等のことを実行できるのは事実ですが (ただし、ここでは関係ありません)、それはポインタではなくvaluesの機能と比較することになります。refout(*ptr)++


refスタックは移動されず、out常にスタックのアクティブな領域を参照するように C# が慎重に編成されているため、それらが内部的に単なるポインターであることは間違いありません。


編集もう一度完全に明確にするために(以下の例からまだ明確になっていない場合)、ここでのポイントはref/がスタックを指すoutことしかできないということではありません。スタックを指している場合、言語規則によってダングリング ポインターにならないことが保証されているということです。スタックはメソッド呼び出しの終了に従って情報を破棄するだけであり、リファラーがまだ存在することを確認するチェックを行わないため、この保証が必要です (そしてここで関連性があり、興味深いものです)。

逆に、ref/outが GC ヒープ内のオブジェクトを参照する場合、それらのオブジェクトを必要なだけ存続させることができることは驚くべきことではありません。 GC 圧縮によってオブジェクトを移動してはならない状況をサポートするために、ピニング (以下の例を参照) を提供します。


ref安全でないコードで相互運用を行ったことがある場合は、それがポインターと非常に密接に関連していることに気付くでしょう。たとえば、COM インターフェイスが次のように宣言されているとします。

HRESULT Write(BYTE *pBuffer, UINT size);

相互運用アセンブリは、これを次のように変換します。

void Write(ref byte pBuffer, uint size);

そして、これを実行してそれを呼び出すことができます(COM相互運用機能が配列の固定を処理すると思います):

byte[] b = new byte[1000];
obj.Write(ref b[0], b.Length);

つまり、ref最初のバイトにアクセスすると、そのすべてにアクセスできます。どうやら最初のバイトへのポインタです。

于 2009-07-22T18:51:00.503 に答える
6

C# の参照パラメーターを使用して、ポインターの1 つの使用を置き換えることができます。すべてではありません。

ポインターのもう 1 つの一般的な用途は、配列を反復処理する手段としてです。Out/ref パラメーターはそれを行うことができないため、「ポインターと同じ」ではありません。

于 2009-07-22T18:50:28.820 に答える
3

refandoutは、引数が値ではなく参照によって渡されることを示すために、関数の引数と共にのみ使用されます。この意味で、はい、C++ のポインターに似ています (実際には参照に似ています)。詳細については、この記事を参照してください。

于 2009-07-22T18:54:51.010 に答える
1

比較は見る人の目にかかっていますが、私はノーと言います。'ref' は呼び出し規約を変更しますが、パラメーターのは変更しません。C++ の例では、d1 と d2 は int* 型です。C# では、それらはまだ Int32 であり、たまたま値ではなく参照によって渡されます。

ところで、あなたの C++ コードは、従来の意味での入力を実際には交換していません。次のように一般化します。

template<typename T>
void swap(T *d1, T *d2)
{
    T temp = *d1;
    *d1 = *d2;
    *d2 = temp;
}

...すべての型 T にコピー コンストラクターがない限り機能しません。その場合でも、ポインターを交換するよりもはるかに非効率的です。

于 2009-07-22T18:58:14.873 に答える
1

簡単に言えば、はい (機能は似ていますが、メカニズムはまったく同じではありません) です。補足として、FxCop を使用してコードを分析する場合、outandrefを使用すると、「CA1045:DoNotPassTypesByReference」の「Microsoft.Design」エラーが発生します。

于 2009-07-22T18:51:46.773 に答える
1

outを使用する利点は、アイテムに値が割り当てられることが保証されていることです。そうでない場合は、コンパイル エラーが発生します。

于 2009-07-22T18:53:21.247 に答える