しばらく検索しましたが、参照型、つまり動的メモリまたはオブジェクトがヒープ上に存在する必要があるのに、値型をスタックに割り当てる必要がある理由について、決定的な答えはありません。なぜ同じものをスタックに割り当てることができないのですか?
5 に答える
彼らはそうすることができます。実際には、スタックはヒープよりも一般的に不足しているリソースであり、スタックに参照型を割り当てるとすぐに使い果たされる可能性があるためではありません。さらに、関数がスタックに割り当てられたデータを返す場合、呼び出し元側でセマンティクスをコピーする必要があります。そうしないと、次の関数呼び出しによって上書きされるものが返されるリスクがあります。
値型(通常はローカル変数)は、ネイティブのマシン命令を使用して、スコープにすばやく簡単に出し入れできます。戻り時の値型のコピーセマンティクスは、ほとんどがマシンレジスタに適合するため、簡単です。これは頻繁に発生するため、可能な限り安価にする必要があります。
値型が常にスタック上に存在するというのは正しくありません。このトピックに関するJonSkeetの記事を読んでください。
スタックパラダイム (ネストされた割り当て/割り当て解除) は、ネストされていないオブジェクトの有効期間を必要とする特定のアルゴリズムを処理できないことを理解しています。
静的な割り当てパラダイムが再帰的なプロシージャ コールを処理できないのと同じように。(例えば、f(n-1) + f(n-2) としての fibonacci(n) の素朴な計算)
ただし、この事実を説明する単純なアルゴリズムは知りません。任意の提案をいただければ幸いです:-)
ローカル変数はスタックに割り当てられます。そうでない場合は、変数のメモリを割り当てるときに、変数がヒープを指すようにすることはできません。必要に応じてスタックに割り当てることができます。ローカルで十分な大きさのバッファを作成し、自分で管理するだけです。
メソッドがスタックに置くものはすべて、メソッドが終了すると消えます。.net と Java では、クラス オブジェクトへの最後の参照が消えるとすぐにクラス オブジェクトが消えることは完全に許容されます (実際には望ましいことです)。一般に、メソッドがオブジェクトを作成するときに、そのオブジェクトへの参照がメソッドの終了後も存在し続けるかどうかをコンパイラが知ることはできません。そのような保証がない場合、クラス オブジェクトを割り当てる唯一の安全な方法は、それらをヒープに格納することです。
ちなみに、.net では、変更可能な値の型の主な利点の 1 つは、それらに対する永続的な制御を放棄することなく、参照によって渡すことができることです。クラス 'foo' またはそのメソッドが、foo のメソッドの 1 つが参照によってメソッド 'bar' に渡す構造体 'boz' を持っている場合、bar またはそれが呼び出すメソッドは、必要なことを何でも実行できます。 boz' は返されるまで保持されますが、'bar' が保持していた参照が返されると、'boz' への参照は失われます。これにより、多くの場合、クラス オブジェクトに使用される無差別に共有可能な参照よりも、はるかに安全でクリーンなセマンティクスが得られます。