web-dev-qa-db-ja.com

std :: stringのc_str()からどのようなパフォーマンスを期待できますか?常に一定の時間?

最近、必要な最適化をいくつか行っています。私が行っていることの1つは、ostringstreams-> sprintfsを変更することです。私は一連のstd :: stringsをcスタイルの配列alaにsprintf 'しています

char foo[500];
sprintf(foo, "%s+%s", str1.c_str(), str2.c_str());

Microsoftのstd :: string :: c_str()実装は一定の時間で実行されることがわかります(内部ポインターを返すだけです)。 libstdc ++でも同じ のようです。 stdがc_strを保証しないことを私は理解していますが、これを行う別の方法を想像するのは困難です。たとえば、メモリにコピーした場合、メモリをバッファに割り当てる必要があります(それを呼び出し側に任せて破棄します-STLコントラクトの一部ではありません)OR they内部の静的バッファにコピーする必要があります(おそらくスレッドセーフではなく、その存続期間は保証されていません)したがって、内部で保持されているnullで終了する文字列にポインタを返すだけが現実的な解決策のようです。

13
Doug T.

思い出すと、標準ではstring::c_str()が満足するほとんどすべてのものを返すことができます。

  • 文字列の内容と終了NULLに十分な大きさのストレージ
  • 指定されたstringオブジェクトの非constメンバーが呼び出されるまで有効でなければなりません

したがって、実際には、これは内部ストレージへのポインタを意味します。返されたポインタの寿命を外部から追跡する方法がないためです。あなたの最適化は、これが(小さい)一定の時間であると仮定しても安全だと思います。

関連する注記として、文字列のフォーマットがパフォーマンスを制限している場合。 Boost.Phoenix のようなもので絶対に必要になるまで評価を延期するより良い運が見つかるかもしれません。

Boost.Format結果が必要になるまで内部的にフォーマットを延期すると思います。フォーマット文字列を再解析せずに同じフォーマットオブジェクトを繰り返し使用できます。これにより、高頻度のログ記録に大きな違いが生じることがわかりました。

9
rvalue

C++ 11標準(N 3290バージョンを読んでいます)では、21.4.7.1章でc_str()メソッドについて説明しています。

const charT* c_str() const noexcept; const charT* data() const noexcept;

戻り値:[0、size()]の各iに対してp + i ==&演算子となるようなポインターp。
複雑さ:一定時間
要件:プログラムは、文字配列に格納されている値を変更してはなりません。

したがって、はい:一定の時間の複雑さは標準によって保証されています。

C++ 03標準を確認したところ、そのような要件はなく、複雑さもわかりません。

23
BЈовић

理論的にはC++ 03はそれを必要としないため、文字列は、c_str()が呼び出されたときにnullターミネータの存在が追加されるcharの配列にすることができます。これには再割り当てが必要な場合があります(内部プライベートポインターがmutableとして宣言されている場合は、定数に違反しません)。

C++ 11はより厳密です。時間のコストがかかるため、再配置を行うことはできず、配列は常に最後にnullを格納するのに十分な幅でなければなりません。 c_str()自体は、「ptr[size()]='\0'」を実行して、nullが実際に存在することを保証できます。範囲[0..size())は変更されないため、配列の定数に違反しません。

8