2017-04-11 8 views
2

C#7.0のリファレンス機能が導入されて以来、このような機能にはヒープ上にある変数にのみこの参照を格納するためにコンパイラの再配線が必要になるとの認識に基づいて、スタック上の変数への参照を返すか、または新しいref宣言が変数が常にヒープに格納されていることを確認しますか?C#7.0で参照によって返される値は、スタックまたはヒープに格納されますか?

ref int x = ref DoSomething(data); 
// Is the value of x now on the stack or the heap? Or is x stored on the stack as a reference and the value on the heap? 

私の理解では、this articleに基づいています。最後に

は、CLRは「REF戻り値の型」を認めていません。理論的には に、 整数変数への参照を返したメソッド "ref int M(){...}"があります。いくつかの奇妙な理由で、 をC#でコンパイラとベリファイアを修正して、 が確実にヒープ上にあることがわかっている変数への参照を返すことができるようにしなければならない、またはスタック上で "lower down"と指定されている場合は、 を呼び出してください。

+0

ローカル変数の場合は、確実にスタックに置かれます。 –

+1

@EhsanSajjadローカル変数の場合は、 'ref'を返すメソッドから返すことができませんでした。 – Servy

+0

@Servyとは何を意味するのでしょうか? –

答えて

10

"Haddocks 'Eyes"と呼ばれます。 「ああ、それは歌の名前ですか?」アリスは興味を感じようとしていました。 「いいえ、分かりません」とナイトは少し腹が立っていると言っていました。それは名前が呼ばれるものです。名前は本当に「老人」です。 'それで、「それは、その曲が何と呼ばれているのですか」と言わなければならないのですか?アリスは自分自身を修正した。 'いいえ、それはまったく別のものです。この曲は「Ways and Means」と呼ばれていますが、それはそれが唯一のものです。 「さて、その曲は何ですか?」この時までに完全に困惑していたアリスは言った。 「私はそれに来ていました」とナイトは言いました。 「この曲は本当に「A-sitting on a Gate」であり、その曲は自分の発明です。

曲の名前、曲の名前、名前の名前、曲の名前は明らかにすべて異なります。


あなたが混同してはならない3つのことをあります

  • 変数から参照の場所 - 別名
  • という変数が参照される変数 - には、別名という変数があります。
  • 参照先の変数が参照型の場合は、参照されている変数の位置を参照します。

ref int x = ref DoSomething(data); 

スタックやヒープ上に今のxの値はありますか?

発現xは別の変数から別名です。

その変数には値があります。

エイリアス化された変数が値型であるとします。一時プール(別名「スタック」)または長期プール(「ヒープ」)のエイリアス化された変数、したがってその値はありますか?私たちは知らない。私たちも気にしません。私たちは、それがどれであっても、この変数が現在生きていることが保証されています。

しかし、我々は推測を行うことができます:refはは、我々は、彼らが生きていることを確実に知るための変数は、ヒープ割り当てられた変数へ通常別名です戻りました。

エイリアス化された変数が参照型であるとします。 は参照またはがスタックまたはヒープに格納されていますか?繰り返しますが、我々は同じ理由で、わかりません。 はその参照の参照先ですか?はスタックまたはヒープにありますか?それはヒープ上にあるか、またはヌルです。私たちです。

または、xは参照としてスタックに格納され、ヒープの値は? xことで

あなたは変数がxエイリアスこと、またはあなたがローカルx自体を意味していますを意味していますか?ローカル自体は、スタックまたはレジスタのいずれかに格納されます。クロージャークラスのフィールドには絶対に持ち込まれません。変数のエイリアスはどこでもかまいませんが、上記のように、ヒープ上にある可能性が高いです。

+0

私はあなたの答えが大好きです。しかし、C#7ではエイリアスを作成した時点で変数が確実に生きていることをどのように保証していますか?私は現時点でそれを試すことはできませんが、同じメソッドの作業でローカル変数(スタック上)への参照を返さないのですか? – IllidanS4

+0

@ IllidanS4:コンパイラは、それぞれのrefがどこから来たのか、どうなるのかを追跡する必要があります。私たちが知っている参考文献を地元に返すことは合法ではありません。 –

+0

すべての場合にそうすることはできますか?すでにコンパイルされた別のアセンブリでref-returning ref-takingメソッドがあり、それが提供された参照のみを返す場合はどうなりますか?この場合でもコンパイラはメソッドをチェックしますか? – IllidanS4

7

ref int xは、実行時に変数が動作する方法であるint* xのシンタックスシュガーです。引数としてメソッドに変数を渡し、パラメータが宣言された場合は、refの呼び出し元が変数へのポインタを渡すときとまったく同じ動作をします。ポインタは、値が格納されている場所を気にせず、実際にはどこにでも格納できます。プロパティを渡すことはできませんが、記憶域はありません。

C#v7でやらなければならないことは、間違いなくdangling pointer bugを作成できないようにすることです。 CやC++などの言語では、コンパイラが診断を生成する必要はなく、これらの言語では未定義の動作です。そのバグを持つプログラムの多くは、プログラムの一見些細な変更(関数呼び出しの追加)が指し示された値を破損するまで、正常に動作するように見えます。

afaikを実際に実行するのは難しくありませんが、呼び出されたメソッドのローカル変数はトラブルメーカーです。メソッドが戻った後も存在しなくなり、参照が無効になります。特定のシナリオでは、C#v7でコンパイルエラーが発生します。しかし、ローカル変数が呼び出し側の変数の1つであり、変数がまだ生きているパラメータを介して参照を渡しても問題ありません。

関連する問題