「C ++パフォーマンス・チューニング・ガイド」の第4章:文字列の使用を最適化

第4章:文字列の使用を最適化

C ++のstd ::文字列のために説明。

3つの文字列の4.1特性

(1)文字列が動的に割り当てられる
  理由:文字バッファのサイズは、文字列内に固定され、可変長文字列の操作がある場合、発生することがあり、文字列のサイズは、その内部バッファの長さを超えます、メモリマネージャのmalloc /文字列バッファと自由の新しいコピーに新しい新しいバッファから生じた/元の空間を削除します。
  理由の発生の可能性は、いくつかの実装文字列のサイズは、文字バッファ・アプリケーションである、上記で説明格納された文字の二倍の数を必要とします。

(2)基準ではなく、文字列の値である
  文字列でないバイトの組み合わせとして、まとまりとして扱うべきである、と言うことです。例えば:
  1)割り当て=コピー:別の文字列に割り当てられた文字列は、各文字列変数は、その格納されたコンテンツのプライベートコピーを有しています。
  2)中間体発現は、一時的な値を=:中間結果の値は、文字列表現です。
    たとえば、次のように、S1 = S2 + S3 + S4 、
     新しい一時的な文字列S2 + S3 mallocとコピーされます、+ S4がさらにmalloc関数、文字列と新しい一時的なコピーと自由は、合計して、以前の値= S1、および自由に置き換えられますでしょう2のmalloc、2回無料、5回のコピーがあります。
    

(3)文字列の質量の複製のための
  文字列、割り当てを作成する場合、または関数へのパラメータとして渡され処理される文字列の値として、コピー後であり、通過するパラメータのオーバーヘッドを割り当てることと多くの変更が、関数変異機能とconst参照のオーバーヘッドの値が非常に小さい変化します。
  オーバーヘッド操作を渡す文字列、割り当てとパラメータを達成するために、書き込みのコピーオンライトコピーした場合、COWの方法は非常に小さいが、文字列が共有されると、同様の機能のいずれかの非const参照変数の値を呼び出すことで、すべてが高価必要割り当てとコピー操作。ただ素晴らしいとオーバーヘッドを書くときに並行コードでは、文字列をコピーします。すべての変数値関数およびconst参照は、参照カウンタを訪問するべきです。参照カウントが複数のスレッドによってアクセスされる場合、各スレッドは、他のスレッドが値を変更しないことを保証するために、メインメモリ内の参照カウントのコピーから特別な命令を取得しなければなりません。だから、実際には、でもコピーはC ++ 11標準実装時の書き込みと一致するだけでなく、非常に問題ではありません。
  「右辺値参照」と「移動セマンティクス」移動コンストラクタ呼び出しではなく、コピーコンストラクタ。

4.2ケース:最適化メモリの割り当てと文字列のコピー操作

# 待优化的函数
std::string remove_ctrl(std::string s) {
    std::string result;
    for (int i = 0; i < s.length(); ++i) {
        if (s[i] >= 0x20)
            result = result + s[i];
    }
    return result;
}

最適化:

(1)一時的な文字列を避けるために、化合物代入演算子を使用して

result += s[i]; perf boost +13x

  すべてので、削除一時的な文字列を操作する)関連のコピー、3)2、メモリマネージャへの呼び出しを接続した結果を保持するために新しい一時的な文字列オブジェクトの場合)1を削除しました。

(2)メモリの再割り当てによって確保されたメモリ空間を使用して

result.reserve(s.length()); perf boost +17%

  予備()関数は、事前に十分なメモリを割り当てますので、だけでなく、削除、再分配文字列バッファは、バッファは、キャッシュローカリティローカリティデータは機能を読んで改善します。

(3)重複パラメータ文字列の除去が、反復解法を使用する必要がポインタプライマーを排除します

# 常量引用 作为函数参数
remove_ctrl(std::string const& s) perf boost -8%

  参照変数はポインタによって達成され、プログラムの発生プライマーソリューションは、ポインタ操作を発生するたびに、PERF原因は、反復解法が保存操作つながることができますのでことを、減少しました。

for (auto it=s.begin(),end=s.end(); it != end; ++it) {  perf boost +41%
    if (*it >= 0x20)
        result += *it;
}

  呼び出しのオーバーヘッドのセーブ以上反復操作、およびループ初期化(のキャッシュs.end)を、達成するために。
  関数パラメータの代わりに文字列参照remove_ctrl(STD ::文字列&S)は 、 また、PERF + 16%が、もはや一定の基準揚力を高めることができます。

返される文字列の複製の(4)撤廃

remove_ctrl(std::string& result, std::string const& s) {  perf boost +2%
    result.clear();
    ...
}

  少しパフォーマンスの向上が、インターフェイスを変更する必要があります。

(5)あるいは文字列の文字列

void remove_ctr_cstring(char* destp, char const* scrp, size_t size) {  perf boost +6x
    for (int size_t i=0; i < size; ++i) {
        if (srcp[i] >= 0x20)
             *desp++ = scrp[i];
    }
    *desp = 0;
}

  C静的大きな一時バッファを宣言するC ++の文字列の文字列を、置換の静的配列を使用して。その理由のパフォーマンスは、コール、いくつかの機能と改善キャッシュの局所性を除去するものであるが、インターフェースの変更は巨大です。

概要:深さの最適化がパフォーマンスの改善目標、より性能の向上、より大きな作業負荷、2/8原則の使用によって決定されます。

ケース4.2:最適化文字列に他の方法の使用

(1)は、より良いアルゴリズムを使用します

for (size_t b=0, i=b, e=s.length(); b < e; b=i+1) {
    for (i=b; i < e; ++i) {
        if (s[i] < 0x20)
            break;
    }
    result = result + s.substr(b, i-b);
}
b   i+1     e
|   |       |
xxxxxxx...xxx
|__|_|
i

  上記のアルゴリズムではなく、単一の文字のコピーよりも、文字列のサブコピーです。
若しくは

result.append(s, b, i-b); 添加子串,而非创建临时字串。
s.erase(i, 1); 删除某字符,而非创建临时字串。

(2)優れたコンパイラの
  ICC

(3)良好文字列ライブラリの使用
  ブースト文字列ライブラリ
  C ++ストリングツールキットStrTk
  STD ::メモリ割り当てが生じないように、動的バッファが大きカプセル化にstringstreamは、一時的な文字列を作成しませんそしてコピー操作は、利点は、コードの文字列を記述するのは非効率避けるためですが、パフォーマンスがのstd ::文字列より良くなることはありません。
  std :: string_view

(4)良好アロケータの使用
  tcmallocの

注意点:
(1)「のMyString」は、文字列定数であり、とstd :: stringは異なり、メモリの割り当てとコピー操作スイッチング動作が生じます。
等の異なる文字セットとの間(2)変換、比較的ASCII、UTF-16、UTF-8文字セットは、より多目的です。

おすすめ

転載: www.cnblogs.com/qccz123456/p/11917996.html