35

C ++プライマー 言う

ほとんどのアプリケーションでは、安全であるだけでなく、C スタイルの文字列よりもライブラリ文字列を使用する方が効率的です。

安全性が分かります。C++ 文字列ライブラリがより効率的なのはなぜですか? 結局のところ、文字列は依然として文字配列として表現されているのではないでしょうか?

明確にするために、著者はプログラマーの効率 (理解されている) または処理の効率について話していますか?

4

8 に答える 8

28

C 文字列は malloc/new を呼び出さないため、通常は高速です。しかし、より速い場合がstd::stringあります。関数strlen()は O(N) ですが、std::string::size()O(1) です。

また、部分文字列を検索する場合、C 文字列では'\0'、すべてのサイクルでチェックする必要がありますが、そうでstd::stringはありません。'\0'単純な部分文字列検索アルゴリズムでは、 をチェックする代わりに をチェックする必要があるため、あまり問題になりませんi<s.size()。しかし、最新の高性能部分文字列検索アルゴリズムは、文字列をマルチバイト単位でトラバースします。'\0'また、すべてのバイトをチェックする必要があるため、速度が低下します。memmemこれが、GLIBCが よりも 2 倍高速である理由ですstrstr。部分文字列アルゴリズムのベンチマークをたくさん行いました。

これは、部分文字列検索アルゴリズムだけではありません。他の多くの文字列処理アルゴリズムは、ゼロで終了する文字列の処理が遅くなります。

于 2012-08-25T18:07:31.343 に答える
25

C++ 文字列ライブラリがより効率的なのはなぜですか? 結局のところ、文字列は依然として文字配列として表現されているのではないでしょうか?

慎重に書かないと効率が悪くなる可能性が高いためchar*です。char[]たとえば、次のようなループを見たことがありますか。

char *get_data();

char const *s = get_data(); 

for(size_t i = 0 ; i < strlen(s) ; ++i) //Is it efficent loop? No.
{
   //do something
}

それは効率的ですか?いいえ。 の時間計算量はstrlen()O(N)あり、さらに、上記のコードでは反復ごとに計算されます。

「一度電話すれば効率化できる」というstrlen()方もいらっしゃるかもしれません. もちろん、できます。しかし、そのような最適化はすべて、自分意識的に行う必要があります。何かを見逃した場合は、CPU サイクルを逃したことになります。しかし ではstd::string、そのような最適化の多くはクラス自体によって行われます。したがって、これを書くことができます:

std::string get_data();

std::string const & s = get_data(); //avoid copy if you don't need  it

for(size_t i = 0 ; i < s.size() ; ++i) //Is it efficent loop? Yes.
{
   //do something
}

それは効率的ですか?はい。の時間複雑度はsize()ですO(1)。手動で最適化する必要はありません。これにより、コードが見苦しく読みにくくなることがよくあります。で得られたコードstd::stringは、 と比較して、ほとんどの場合、きれいでクリーンchar*です。

std::stringまた、CPU サイクルに関してコードが効率的になるだけでなく、プログラマーの効率も向上することに注意してください。

于 2012-08-25T17:59:15.487 に答える
9

Astd::stringはその長さを知っているため、多くの操作が高速になります。

たとえば、次のようになります。

const char* c1 = "Hello, world!";
const char* c2 = "Hello, world plus dog!";
std::string s1 = c1;
std::string s2 = c2;

strlen(c1)より遅いですs1.length()。比較の場合、strcmp(c1, c2)複数の文字を比較して文字列が等しくないことを確認する必要がありs1 == s2ますが、長さが同じではないことがわかり、すぐに false を返します。

他の操作も、事前に長さを知ることから恩恵を受けます。たとえば、データを追加する場所を見つけるstrcat(buf, c1)ために null ターミネータを見つける必要がありますが、すでに長さを知っているため、新しい文字を適切な場所にすぐに追加できます。bufs1 += s2s1

メモリ管理に関してstd::stringは、成長するたびに追加のスペースを割り当てます。つまり、将来の追加操作で再割り当てする必要はありません。

于 2012-08-25T18:05:05.097 に答える
7

std::string勝る場合がありchar[]ます。たとえば、C スタイルの文字列では通常、明示的な長さが渡されません。代わりに、NUL ターミネータが暗黙的に長さを定義します。

これは、挿入ポイントを決定するために各ループが文字列全体を処理する必要があるため、継続的に a にstrcatsするループchar[]が実際に O(n²) の作業を実行していることを意味します。strcat対照的にstd::string、文字列の末尾に連結するために a が実行する必要がある唯一の作業は、新しい文字をコピーすることです (場合によってはストレージを再割り当てしますが、公平に比較​​するには、事前に最大サイズを知っておく必要がありreserve()ます) 。 .

于 2012-08-25T17:58:20.527 に答える
3

文字列は、文字列とそのサイズやその他の機能を含むオブジェクトです。文字列ライブラリの文字列を使用すると、メモリの割り当てや割り当て解除、メモリリークやその他のポインタの危険性を防ぐことができます。ただし、文字列はオブジェクトであるため、メモリ内に余分なスペースが必要になります。

Cstringは単なる文字配列です。リアルタイムで作業しているときに使用する必要があります。手元にあるメモリスペースの量が完全にわからない場合。cstringsを使用している場合は、メモリの割り当てに注意し、strcpyまたは文字ごとにデータをコピーしてから、使用後に割り当てを解除する必要があります。したがって、頭痛の種を避けたい場合は、文字列ライブラリの文字列を使用することをお勧めします。

文字列はプログラムの効率を高めますが、処理の効率を下げます(必ずしもそうとは限りません)。逆もまた同様です。

于 2012-08-25T17:50:42.000 に答える
3

まあ、(実行時間に関して)実質的により効率的になる方法は明らかで単純なことは、データとともに文字列の長さを保存することです(または、少なくともsizeメソッドはO(1)でなければなりません。これは実質的に同じです) .

したがって、C 文字列で NUL 文字を検索する必要がある場合 (したがって、文字列全体を 1 回ウォークする場合) はいつでも、定数時間でサイズを取得できます。そして、これはかなり頻繁に起こります。たとえば、文字列をコピーまたは連結して、サイズを知る必要がある新しい文字列を事前に割り当てる場合などです。

しかし、これが著者の意図したことなのか、それとも実際に大きな違いをもたらすのかはわかりませんが、それでも有効なポイントです。

于 2012-08-25T18:02:18.420 に答える
1

C スタイルの文字列の難しさは、それらが含まれているデータ構造について知らなければ、実際には多くのことを行うことができないということです。たとえば、「strcpy」を使用する場合、宛先バッファが書き込み可能であり、ソースの最初の 0 バイトまですべてを格納するのに十分なスペースがあることを知っておく必要があります (もちろん、あまりにも多くの場合、実際にはそうではありません)。確かにそれを知っている...)。要求に応じてスペースを割り当てることをサポートするライブラリ ルーチンはほとんどなく、無条件に割り当てることで機能するライブラリ ルーチンはすべて機能すると思います (つまり、1000 バイトのスペースを持つバッファがあり、900 バイトの文字列をコピーしたい場合、コードこれらのメソッドを使用すると、1000 バイトのバッファーを破棄してから、新しい 900 バイトのバッファーを作成する必要がありますが、1000 バイトのバッファーを単純に再利用する方がよい場合もあります)。

多くの場合、オブジェクト指向の文字列型を操作することは、標準の C 文字列を操作するほど効率的ではありませんが、物を割り当てて再利用する最適な方法を見つけ出します。一方、文字列を最適に割り当てて再利用するように作成されたコードは非常に脆弱である可能性があり、要件をわずかに変更すると、コードに多くのトリッキーな微調整が必​​要になる可能性があります。コードを完全に微調整しないと、バグが発生する可能性があります。明らかで深刻な場合もあれば、微妙だがさらに深刻な場合もあります。標準 C 文字列を使用するコードの脆弱性を回避する最も実用的な方法は、非常に保守的に設計することです。入力データの最大サイズを文書化し、大きすぎるものはすべて切り捨て、すべてに大きなバッファーを使用します。実行可能ですが、それほど効率的ではありません。

対照的に、オブジェクト指向の文字列型を使用する場合、それらが使用する割り当てパターンは最適ではない可能性がありますが、「すべてを大きく割り当てる」アプローチよりも優れている可能性があります。このように、手作業で最適化されたコード アプローチのランタイム効率の多くと、「すべてを大きく割り当てる」アプローチよりも優れた安全性が組み合わされています。

于 2012-08-25T18:11:48.207 に答える
1

ここに短い視点があります。

まず第一に、C++ 文字列はオブジェクトであるため、オブジェクト指向言語で使用する方が一貫性があります。

次に、標準ライブラリには、文字列、イテレータなどの便利な関数が多数付属しています。これらはすべて、再度コーディングする必要がないため、時間を節約でき、このコードには (ほぼ) バグがないことを確認できます。 .

最後に、C の文字列はポインターであり、初心者には理解するのが難しく、複雑さをもたらします。C++ ではポインターよりも参照が優先されるため、C 文字列の代わりに std::string を使用する方が理にかなっています。

私が助けてくれることを願っています。

于 2012-08-25T17:52:52.067 に答える