web-dev-qa-db-ja.com

std :: stringは、メモリを自然に返さないことが保証されていますか?

std::stringは、より小さいサイズの文字列から再割り当てされた場合、割り当てられたメモリを自発的に返しませんか?

言い換えると:

std::string str = "Some quite long string, which needs a lot of memory";
str = "";
str = "A new quite long but smaller string"; // Guaranteed to not result in a heap allocation?

ヒープの断片化を避けるためにこれに依存しているので、私は尋ねます。

31
Martin G

いかなる保証もありません。

[string.cons]/36 は、移動割り当てに関してconst char*std::stringを割り当てることを定義します。定義は次のとおりです。

[string.cons]/32

basic_string& operator=(basic_string&& str)  noexcept(/*...*/)

Effects:反復子、ポインター、参照が無効になる場合を除き、割り当てをシーケンスコンテナーとして移動します。

これは、委員会が、実装に無効化操作とより保守的な操作を自由に選択させることを示しています。そして、物事をさらに明確にするために:

[basic.string]/4

basic_­stringシーケンスの要素を参照する参照、ポインター、および反復子は、そのbasic_­stringオブジェクトの次の使用によって無効になる場合があります。

  • (4.1)非const basic_­stringへの参照を引数として取る標準ライブラリ関数への引数として。
  • (4.2)operator[]atdatafrontbackbeginrbeginend、およびrendを除く非定数メンバー関数の呼び出し。

ヒープの断片化を避けるためにこれに依存しているので、私は尋ねます。

std::stringは、テンプレートパラメータとしてアロケータを取ります。ヒープの断片化の可能性に本当に関心がある場合は、独自のコードを作成できます。これには、いくつかのヒューリスティックを使用して、ニーズに合った割り当て戦略を設定できます。

実際には、私が知っているほとんどの実装は、あなたの質問の場合にメモリを再割り当てしません。これは、実装ドキュメントと最終的にソースコードをテストまたは確認することで確認できます。

35
YSC

CPPリファレンス は、charへのポインターへの割り当てを示しています

* this = basic_string(s)のようにsが指すヌル終了文字列の内容で内容を置き換えます。これにはTraits :: length(s)の呼び出しが含まれます。

この「あたかも」は実際には右辺値の割り当てに要約されるため、次のシナリオは非常に可能です。

  1. 新しい一時文字列が作成されます。
  2. This文字列は、右辺値参照への割り当てを介してコンテンツを盗み出します。
13
bipll

文字列が短く(コンパイラ/ std libに応じて最大15または22バイト)、C++ 11以降のモードで比較的最近のコンパイラを使用している場合は、 短い文字列の最適化 (SSO)。この場合、文字列の内容はヒープに個別に割り当てられません。

このリンクには、一般的な実装と割り当て戦略に関する多くの詳細も含まれています。

ただし、例の両方の文字列はSSOには長すぎます。

2
Paul Floyd