C# の ref と out は C++ のポインタと同じですか?
質問
C# で次のようなスワップ ルーチンを作成しました。
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;
}
も同様です ref
そして out
C# のポインタなどのキーワードを使用せずに unsafe
コード?
解決
それらはさらに制限されています。ポインタに対しては ++ と言うことができますが、 ref
または out
.
編集 コメントにはいくつかの混乱があるため、完全に明確にしておきます:ここでのポイントは、ポインターの機能と比較することです。と同じ操作はできません ptr++
に ref
/out
, 、つまりメモリ内の隣接する位置をアドレス指定します。以下と同等のことを実行できるのは事実です (ただし、ここでは関係ありません)。 (*ptr)++
, しかしそれは、の能力と比較することになります。 価値観, ポインタではありません。
スタックは移動されず、C# は慎重に編成されているため、内部的には単なるポインターであると考えて間違いありません。 ref
そして out
常にスタックのアクティブな領域を参照します。
編集 もう一度完全に明確にしておきます(以下の例でまだ明らかでない場合)、ここでのポイントは次のことではありません。 ref
/out
できる のみ スタックをポイントします。それは いつ これはスタックを指しますが、言語規則によって、ダングリング ポインタにならないことが保証されています。スタックはメソッド呼び出しの終了に従って情報を破棄するだけで、リファラーがまだ存在するかどうかを確認しないため、この保証は必要です (そしてここで関連性があり、興味深いものです)。
逆に言うと ref
/out
GC ヒープ内のオブジェクトを参照します。これらのオブジェクトが必要な限り存続できることは驚くべきことではありません。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
最初のバイトにアクセスすると、そのすべてにアクセスできます。どうやら最初のバイトへのポインタのようです。
他のヒント
参照パラメータは、はい、ポインタのの1 の使用を置き換えるために使用することができます。すべてではありません。
のポインタのための別の一般的な使用は、アレイを反復するための手段としてです。アウト/ refのパラメータはありませんので、彼らは「ポインタと同じ」ではない、ということはできません。
実は、私はC ++の参照ではなく、ポインタにそれらを比較したいです。ポインタは、C ++やCで、より一般的な概念であり、参照はあなたがやりたいだろう。 これらのすべては、間違いなく、もちろん、カバーの下にポインタされます。ref
とout
のみ引数が参照代わりの値によって渡されることを意味する関数の引数で使用されています。この意味では、そう、彼らは多少C ++(実際の参照のようなより)内のポインタのようなものです。この記事のnoreferrer">
のうちのを使用してのいいところは、あなたが項目に値が割り当てられますことを保証しているということである - 。ない場合は、コンパイルエラーが発生します。
比較は見る人の目次第ですが...私はノーと言います。'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 にコピー コンストラクターがない限り機能しませんが、それでもポインターを交換するよりもはるかに非効率的です。
短い答えはYesです(同様の機能ではなく、まったく同じメカニズム)。
サイドノートとして、あなたはの「Microsoft.Design」エラーになりますout
とref
を使用して、あなたのコードを分析するためにFxCopのを使用する場合、「CA1045:。DoNotPassTypesByReference」