8

C++ の文字列に関して次の質問があります。

1>>(パフォーマンスを考慮して)どちらがより良いオプションで、その理由は?

1.

string a;
a = "hello!";

また

2.

string *a;
a = new string("hello!");
...
delete(a);

2>>

string a;
a = "less"; 
a = "moreeeeeee"; 

大きな文字列が小さな文字列にコピーされるときに、C++ でメモリ管理がどのように正確に処理されますか? C++ 文字列は変更可能ですか?

4

9 に答える 9

8

以下はすべて、素朴なコンパイラが行うことです。もちろん、プログラムの動作を変更しない限り、コンパイラは自由に最適化を行うことができます。

string a;
a = "hello!";

最初に、空の文字列を含むように a を初期化します。(長さを 0 に設定し、他の 1 つまたは 2 つの操作を行います)。次に、すでに設定されている長さの値を上書きして、新しい値を割り当てます。また、現在のバッファーの大きさと、さらにメモリを割り当てる必要があるかどうかを確認するために、チェックを実行する必要がある場合もあります。

string *a;
a = new string("hello!");
...
delete(a);

new を呼び出すには、OS とメモリ アロケータがメモリの空きチャンクを見つける必要があります。それは遅いです。次に、すぐに初期化するので、最初のバージョンのように、何かを 2 回割り当てたり、バッファーのサイズを変更したりする必要はありません。その後、何か問題が発生し、delete を呼び出すのを忘れて、割り当てが非常に遅い文字列に加えて、メモリ リークが発生します。だからこれは悪い。

string a;
a = "less"; 
a = "moreeeeeee";

最初のケースと同様に、最初に a を初期化して空の文字列を含めます。次に、新しい文字列を割り当ててから、別の文字列を割り当てます。これらのそれぞれは、より多くのメモリを割り当てるために new の呼び出しを必要とする場合があります。各行には長さも必要であり、場合によっては他の内部変数を割り当てる必要があります。

通常、次のように割り当てます。

string a = "hello";

1行で、最初にデフォルトで初期化してから必要な値を割り当てるのではなく、初期化を1回実行します。

プログラムのどこにも無意味な空の文字列がないため、エラーも最小限に抑えられます。文字列が存在する場合は、必要な値が含まれています。

メモリ管理については、google RAII。つまり、string は new/delete を内部的に呼び出して、バッファーのサイズを変更します。つまり、new で文字列を割り当てる必要はありません。文字列オブジェクトは固定サイズで、スタックに割り当てられるように設計されているため、スコープ外になるとデストラクタが自動的に呼び出されます。デストラクタは、割り当てられたメモリが解放されることを保証します。これにより、ユーザー コードで new/delete を使用する必要がなくなり、メモリ リークが発生しなくなります。

于 2009-02-10T20:34:47.127 に答える
2
string a;
a = "hello!";

2 つの操作: デフォルトのコンストラクター std:string() を呼び出し、次に operator::= を呼び出します

string *a; a = new string("hello!"); ... delete(a);

1 つの操作のみ: コンストラクター std:string(const char*) を呼び出しますが、ポインターを解放することを忘れないでください。

文字列 a("hello"); はどうでしょうか。

于 2009-02-10T20:21:18.500 に答える
0

最も可能性が高い

   string a("hello!");

何よりも速いです。

于 2009-02-11T09:32:26.010 に答える
0

ケース 1.1 では、文字列メンバー(データへのポインターを含む) が保持さstackれ、クラス インスタンスによって占有されていたメモリaはスコープ外になると解放されます。

ケース 1.2 では、メンバーのメモリもヒープから動的に割り当てられます。

定数を文字列に割り当てるchar*と、データを格納するメモリがrealloc新しいデータに合わせて調整されます。

を呼び出すと、割り当てられているメモリの量を確認できますstring::capacity()

を呼び出すとstring a("hello")、コンストラクターでメモリが割り当てられます。

コンストラクターと代入演算子の両方が、同じメソッドを内部的に呼び出して、割り当てられたメモリにアクセスし、そこに新しいデータをコピーします。

于 2009-02-10T20:29:31.163 に答える
0

STL 文字列クラスのドキュメントを見ると(SGI ドキュメントは仕様に準拠していると思います)、メソッドの多くは複雑さの保証をリストしています。複雑さの保証の多くは、さまざまな実装を可能にするために意図的にあいまいなままになっていると思います。一部の実装では、実際にはコピー オン モディファイ アプローチを使用して、1 つの文字列を別の文字列に代入する一定時間の操作を行っていると思いますが、これらのインスタンスの 1 つを変更しようとすると、予期しないコストが発生する可能性があります。ただし、それが最新のSTLでも当てはまるかどうかはわかりません。

capacity()また、メモリの再割り当てを強制される前に、特定の文字列インスタンスに入れることができる最大長の文字列を通知する関数も確認する必要があります。reserve()後で変数に大きな文字列を格納することがわかっている場合は、 を使用して特定の量を再割り当てすることもできます。

他の人が言っているように、例に関する限り、一時オブジェクトの作成を避けるために、他のアプローチよりも初期化を優先する必要があります。

于 2009-02-10T20:30:17.277 に答える
0

基本型を作成する場合と同様に、ヒープに直接文字列を作成することは、通常はお勧めできません。オブジェクトは簡単にスタックに残る可能性があり、効率的なコピーに必要なすべてのコピー コンストラクターと代入演算子があるため、価値はありません。

std:string 自体には、実装に応じて複数の文字列で共有される可能性があるヒープ内のバッファーがあります。

たとえば、Microsoft の STL 実装を使用すると、次のことができます。

string a = "Hello!";
string b = a;

そして、両方の文字列は、変更するまで同じバッファーを共有します。

a = "Something else!";

そのため、後で使用するために c_str() を保存するのは非常に悪いことです。c_str() は、その文字列オブジェクトへの別の呼び出しが行われるまで有効性のみを保証します。

これは、マルチスレッド アプリケーションで共有機能を使用する場合、define を使用してこの共有機能をオフにする必要がある、非常に厄介な同時実行バグにつながります。

于 2009-02-10T20:35:08.467 に答える