web-dev-qa-db-ja.com

string.c_str()割り当て解除が必要ですか?

私のコードは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がヒープ上にあるかどうかを尋ねると、ポインターがスタック上にあることがわかります。 それが指すものがヒープまたはスタックにあるかどうかを尋ねています。

36
_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>_を使用します。

38
Tony Delroy

c_str()は、stringオブジェクトの内部バッファーへのポインターを返します-free()/deleteを使用することはありません。

それが指すstringがスコープ内にある場合にのみ有効です。さらに、stringオブジェクトの非constメソッドを呼び出すと、有効であることが保証されなくなります。

http://www.cplusplus.com/reference/string/string/c_str/

(以下のコメントに基づいて明確にするために編集されています)

15
Brian Roach

std::string::c_str()const char*ではなくchar *を返します。これは、解放する必要がないことを示しています。メモリはインスタンスによって管理されます(たとえば、詳細は このリンク を参照)。そのため、文字列インスタンスが有効である間のみ有効です。

4
vanza

まず、信じられているように、元の文字列でさえスタックに割り当てられていません。少なくとも完全にではない。 _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()が指すメモリの所有者はあなたではありません。割り当てを解除することはできません。あなたはそれがどこに割り当てられているかさえ知っているはずではありません。

4
AnT

_s2_は、sがスコープ内にある限り有効です。 sが所有するメモリへのポインタです。たとえば、 このMSDNドキュメント "文字列には有効期限があり、クラス文字列が所有しています。"

関数内で_std::string_を文字列操作のファクトリとして使用し、Cスタイルの文字列を返す場合は、戻り値にヒープストレージを割り当てる必要があります。 mallocまたはnewを使用してスペースを取得し、s.c_str()の内容をコピーします。

2
japreiss

S2はスタックまたはヒープに割り当てられますか?

どちらでもかまいません。たとえば、std::stringクラスが小さな文字列の最適化を行う場合、データのサイズがSSOしきい値を下回っている場合はデータがスタックに常駐し、それ以外の場合はヒープに常駐します。 (そして、これはすべて、std::stringオブジェクト自体がスタック上にあると想定しています。)

S2を削除する必要がありますか?

いいえ、c_strが返す文字配列オブジェクトは文字列オブジェクトが所有しています。

Originがヒープ上にあったので、s2はヒープ上にありますか?

この場合、SSOを実行する場合でも、データはおそらくヒープに常駐します。ただし、std::stringオブジェクトを動的に割り当てる理由はめったにありません。

場合によります。私の記憶が正しければ、CStringは入力文字列のコピーを作成するので、特別なヒープ割り当てルーチンを用意する必要はありません。

0
Chris K