私のコードはC++文字列をCStringsにいくらか頻繁に変換し、元の文字列がスタックに割り当てられているかどうかを疑問に思っています。CStringもスタックに割り当てられますか?例えば:
string s = "Hello world";
char* s2 = s.c_str();
s2
はスタックまたはヒープに割り当てられますか?つまり、s2
を削除する必要がありますか?
逆に、私がこのコードを持っている場合:
string s = new string("Hello, mr. heap...");
char* s2 = s.c_str();
Originがヒープ上にあったので、s2
はヒープ上にありますか?
明確にするために、s2
がヒープ上にあるかどうかを尋ねると、ポインターがスタック上にあることがわかります。 それが指すものがヒープまたはスタックにあるかどうかを尋ねています。
_string s = "Hello world";
char* s2 = s.c_str();
_
S2はスタックまたはヒープに割り当てられますか?つまり、s2を削除する必要がありますか?
いいえ、しないでください_delete s2
_!
上記のコードが関数内にある場合、_s2
_はスタック上にあります。コードがグローバルスコープまたは名前空間スコープにある場合、_s2
_は静的に割り当てられた動的に初期化されたデータセグメントに含まれます。いずれにせよ、これは文字へのポインタです(この場合、たまたま、s
のテキストコンテンツのASCIIZ表現の最初の_'H'
_文字です)。そのテキスト自体は、s
オブジェクトがその表現を構築したい場所にあります。実装は好きなように行うことができますが、_std::string
_の重要な実装選択は、非常に短い文字列をs
オブジェクトに直接埋め込むことができる「短い文字列の最適化」を提供するかどうかですそして_"Hello world"
_がその最適化から利益を得るのに十分短いかどうか:
s2
_はs
内のメモリを指し、上記の_s2
_で説明したようにスタックまたは静的に割り当てられますs
内には、動的に割り当てられた(フリーストア/ヒープ)メモリへのポインタがあり、.c_str()
によってアドレスが返される "Hello world\0"コンテンツが表示されます。 _s2
_は、そのポインター値のコピーです。c_str()
はconst
であるため、コードをコンパイルするには、_const char* s2 = ...
_に変更する必要があります。
あなたはnot _delete s2
_。 _s2
_が指すデータは引き続きs
オブジェクトによって所有および管理されており、const
の非s
メソッドの呼び出しによって、またはs
範囲外です。
_string s = new string("Hello, mr. heap...");
char* s2 = s.c_str();
_
Originがヒープ上にあったので、s2はヒープ上にありますか?
s
はポインターではなく、文字列にはstring(std::string*)
のようなコンストラクターがないため、このコードはコンパイルされません。次のいずれかに変更できます。
_string* s = new string("Hello, mr. heap...");
_
...または...
_string s = *new string("Hello, mr. heap...");
_
後者はメモリリークを引き起こし、有用な目的を果たさないので、前者を想定しましょう。次に:
_char* s2 = s.c_str();
_
...になる必要があります...
_char* s2 = s->c_str();
_
Originがヒープ上にあったので、s2はヒープ上にありますか?
はい。すべてのシナリオで、特にs
自体がヒープ上にある場合、次のようになります。
c_str()
がポインタを生成するs
内に短い文字列最適化バッファがある場合でも、それはヒープ上にある必要があります。それ以外の場合s
が追加のメモリへのポインタを使用してテキストを格納する場合、そのメモリもヒープから割り当てられます。ただし、_s2
_がヒープに割り当てられたメモリを指していることを確実に知っていても、コードはそのメモリの割り当てを解除する必要はありません。s
が削除されると自動的に行われます。
_string* s = new string("Hello, mr. heap...");
const char* s2 = s->c_str();
...use s2 for something...
delete s; // "destruct" s and deallocate the heap used for it...
_
もちろん、ローカルスコープを超えた存続期間が必要でない限り、通常はstring s("xyz");
を使用する方が適切です。そうでない場合は、_std::unique_ptr<std::string>
_または_std::shared_ptr<std::string>
_を使用します。
c_str()
は、string
オブジェクトの内部バッファーへのポインターを返します-free()
/delete
を使用することはありません。
それが指すstring
がスコープ内にある場合にのみ有効です。さらに、string
オブジェクトの非constメソッドを呼び出すと、有効であることが保証されなくなります。
http://www.cplusplus.com/reference/string/string/c_str/
(以下のコメントに基づいて明確にするために編集されています)
std::string::c_str()
はconst char*
ではなくchar *
を返します。これは、解放する必要がないことを示しています。メモリはインスタンスによって管理されます(たとえば、詳細は このリンク を参照)。そのため、文字列インスタンスが有効である間のみ有効です。
まず、信じられているように、元の文字列でさえスタックに割り当てられていません。少なくとも完全にではない。 _string s
_がローカル変数として宣言されている場合、string
オブジェクト自体のみが「スタックに割り当てられます」。その文字列オブジェクトの制御シーケンスは、別の場所に割り当てられます。どこに割り当てられているかはわかっていませんが、ほとんどの場合、ヒープに割り当てられています。つまり最初の例でs
によって格納された実際の文字列_"Hello world"
_は、s
を宣言する場所に関係なく、通常はヒープに割り当てられます。
次に、c_str()
についてです。
C++(C++ 98)の元の仕様では、_c_str
_は通常、どこかに割り当てられた独立したバッファーへのポインターを返しました。繰り返しになりますが、それがどこに割り当てられているかを知る必要はありませんが、一般的にはヒープに割り当てられるはずでした。 _std::string
_のほとんどの実装では、制御されたシーケンスが常にゼロで終了するようにしたため、それらの_c_str
_は制御されたシーケンスへの直接ポインタを返しました。
C++(C++ 11)の新しい仕様では、_c_str
_が制御シーケンスへの直接ポインターを返すことが必要になりました。
つまり、一般的には、_c_str
_の結果は、ローカルの_std::string
_オブジェクトの場合でも、ヒープに割り当てられたメモリを指します。最初の例は、その点で2番目の例と違いはありません。ただし、いずれの場合でも、c_str()
が指すメモリの所有者はあなたではありません。割り当てを解除することはできません。あなたはそれがどこに割り当てられているかさえ知っているはずではありません。
_s2
_は、s
がスコープ内にある限り有効です。 s
が所有するメモリへのポインタです。たとえば、 このMSDNドキュメント : "文字列には有効期限があり、クラス文字列が所有しています。"
関数内で_std::string
_を文字列操作のファクトリとして使用し、Cスタイルの文字列を返す場合は、戻り値にヒープストレージを割り当てる必要があります。 malloc
またはnew
を使用してスペースを取得し、s.c_str()
の内容をコピーします。
S2はスタックまたはヒープに割り当てられますか?
どちらでもかまいません。たとえば、std::string
クラスが小さな文字列の最適化を行う場合、データのサイズがSSOしきい値を下回っている場合はデータがスタックに常駐し、それ以外の場合はヒープに常駐します。 (そして、これはすべて、std::string
オブジェクト自体がスタック上にあると想定しています。)
S2を削除する必要がありますか?
いいえ、c_str
が返す文字配列オブジェクトは文字列オブジェクトが所有しています。
Originがヒープ上にあったので、s2はヒープ上にありますか?
この場合、SSOを実行する場合でも、データはおそらくヒープに常駐します。ただし、std::string
オブジェクトを動的に割り当てる理由はめったにありません。
場合によります。私の記憶が正しければ、CStringは入力文字列のコピーを作成するので、特別なヒープ割り当てルーチンを用意する必要はありません。