2016-08-20 5 views
1

C++/CLIでは、以下の2つは同じかまたは異なりますか?はスタックまたはヒープ上のこのオブジェクトですか?

System::String ^source("Hello World"); 

System::String ^source= gcnew System::String("Hello World"); 

は、スタック上の最初のものとヒープ上の二番目のですか?
または両方ともヒープになっていますか?
.Netオブジェクト私は、C++とは違ってスタック上には作成できない参照しかないと信じています。誰か説明してもらえますか?

+0

.NETには、ヒープタイプとスタックタイプの両方があります。 – Thomas

+0

@Matteo:C++/CLIはC++ではありません。 – Deduplicator

+0

@Deduplicator:C++/CLIは標準C++と管理対象物を混在させることができるC++のスーパーセットです。 (私のような)C++/CLIで経験を積んだ人の多くは、C++タグに従うが、C++/CLIに従わない人が多いことを考えると、両方のタグを持つことには何の害もありません。純粋なIMOの検索で頑固にC++タグを削除するのはちょうど幼稚園です。 –

答えて

7

文字列はスタックまたはヒープに格納されません。物語はちょっと複雑です。

リファレンスタイプのオブジェクトは常にGCヒープに格納されていると考えるのが便利です。 C++(別名std :: string)とよく似ているが、文字列のような可変長オブジェクトは、フリーストアを使って正しい量のメモリを割り当てる必要がある。 Std :: stringオブジェクト内に非常に短い文字列を格納できる、std :: string内の可能なマイクロ最適化を法とする。しかし、通常はstd :: stringオブジェクト自体をスタックに割り当てることができ、文字列がヒープに割り当てられます。 sourceがスタック上にあるように、ガベージコレクタが元に戻すことができる単純なポインタです。

C言語では、文字列コンテンツをスタックに格納することができますが、必要な文字列バッファの長さを前方に推測する必要があります。何千ものマルウェア攻撃を開始すると、文字列バッファオーバーフローは、プログラムのスタックフレームを混乱させ、関数の戻り値を変更する標準的な手法です。 .NETの方法ではありません。 C言語のコンパイラでは、にはがありません。それらは非常に一般的です。

しかし、あなたが与えた例では単純ではありません。ステートメントの違いはなく、文字列の内容はスタックにもヒープにも割り当てられません。 CLRは、文字列が一致するCLR実装で動作する必要がある文字列を記述するための標準であるCLI仕様を利用するために、極小に最適化されています。

文字列オブジェクトが不変であるという性質を利用しています。これにより、というインターナショナルという最適化が可能になります。文字列オブジェクトは、GCヒープに格納されているように見え、動作します。しかし、実際にはそうではありません、オブジェクトの内容は、アセンブリのメモリマップされたイメージから直接読み取られます。アセンブリメタデータの "blob heap"に格納されます。収集中にこのような文字列オブジェクトに遭遇すると、GCはそれらを無視します。文字列リテラルがC言語でどのように動作するかと非常によく似ています。 10億のクラッシュを起こしたバグを除いて(文字列リテラルはconst char*の代わりにchar*)、不変性保証のために誤って文字列リテラルに書き込むことはできません。

+0

"文字列オブジェクトが不変であるという性質を利用しているため、interningという最適化が可能です。"第2の前提条件があります。つまり、等しい文字列が常に同一である可能性があります。少なくともアセンブリ全体で必須ではありません。ニースポスト。 – Deduplicator

+1

同一の文字列が同じオブジェクトアドレスを持つことは保証されません。CLRは、単一の内部文字列と一致する可能性のある文字列を見つけるためのサイクルを焼き付けません。これはコンパイル時にソートされます。 String.Emptyのような正式な文字列リテラルが* const *の代わりに* readonly *である基本的な理由。 –

+0

System :: Stringは、インスタンスが所定のサイズを持たないCLRの2つの型の1つであると考えると、ストーリーはさらに複雑になります。 –

関連する問題