10

私は現在、Bjarne Stroustrup による「The C++ Programming Language: Special Edition」を読んでおり、133 ページには次のように記載されています。

ユーザー定義型の場合、適切な初期化子が利用可能になるまで変数の定義を延期することも、パフォーマンスの向上につながる可能性があります。例えば:

string s;  /* .... */ s = "The best is the enemy of the good.";

よりもはるかに遅くなる可能性があります。

string s = "Voltaire";

つまり、必ずしもそうであるとは限りませんが、それが発生するとだけ言っておきましょ

これにより、潜在的なパフォーマンスが向上するのはなぜですか?

ユーザー定義型(またはSTL型)でのみそうですか、それとも 、 などの場合intですかfloat?

4

7 に答える 7

9

少なくともパフォーマンスに関する限り、これは主に自明ではないデフォルトコンストラクターを持つ型に関するものだと思います。

2 つのアプローチの違いは次のとおりです。

  • 最初のバージョンでは、(デフォルトのコンストラクターを使用して) 空の文字列が最初に構築されます。次に、割り当て演算子を使用して、デフォルトのコンストラクターによって行われた作業を効果的に破棄し、新しい値を文字列に割り当てます。
  • 2 番目のバージョンでは、必要な値が構築時にすぐに設定されます。

もちろん、これがどの程度のパフォーマンスの違いを生むかを先験的に判断するのは非常に困難です。

于 2012-01-18T17:29:45.117 に答える
7
  1. デフォルトコンストラクタの実行には時間がかかります。後で呼び出される代入演算子で文字列を初期化したものをオーバーライドするのにも時間がかかります。

  2. 関数が (returnステートメントまたは例外により) デフォルト コンストラクターと代入演算子の呼び出しの間に残っている場合、実行が代入に到達しない可能性があります。その場合、オブジェクトは不必要にデフォルトで初期化されました。

  3. 実装は、例外がスローされた場合にオブジェクトのデストラクタが確実に呼び出されるようにするために、パフォーマンスを浪費する可能性があります。到達することのない後続のスコープでオブジェクトが初期化される場合、それも必要ありません。

于 2012-01-18T17:29:47.577 に答える
1

なぜなら:

string s;  /* .... */ s = "The best is the enemy of the good.";    

2 つの操作が含まれます: 構築と代入

その間:

string s = "Voltaire";   

建設のみを含みます。

これは、コンストラクタ本体の代入よりもメンバー初期化リストを選択することと同じです。

于 2012-01-18T17:30:48.063 に答える
0

それは良い質問です。そうです、これは複合型でのみ発生します。つまり、クラスと構造体、std::string はそのようなオブジェクトです。ここに含まれる実際の問題は、コンストラクターに関係しています。

オブジェクトが作成されるとき、つまり

std::string s;

コンストラクターが呼び出され、おそらくメモリが割り当てられ、他の変数の初期化が行われ、使用できるようになります。実際、コードのこの時点で大量のコードが実行される可能性があります。

後で次のようにします。

s = "hello world!";

これにより、クラスは行ったことのほとんどを破棄し、その内容を新しい文字列に置き換える準備をしなければならなくなります。

変数が定義されているときに値を設定すると、これは実際には単一の操作に削減されます。

std::string s = "Hello world";

実際、デバッガーでコードを見ると、オブジェクトを構築してから個別に値を設定する代わりに、別のコンストラクターを 1 回実行します。実際、前のコードは次のようになります。

std::string s("Hello world");

それが物事を少し明確にするのに役立ったことを願っています。

于 2012-01-18T17:31:05.907 に答える
0

両方の場合に何が起こるかを考えてみましょう。最初のケースでは:

  • "s" に対して呼び出されるデフォルトのコンストラクター
  • 「s」に対して呼び出される代入演算子

2 番目のケースでは、最初にコピー省略を使用すると、これが と同等になることを考慮してください。つまり、次string s("Voltaire")のようになります。

  • 呼び出された c-string コンストラクター

論理的には、最初のアプローチでは、抽象マシンがより多くの作業を行う必要があります。これが実際によりリアルなコードに変換されるかどうかは、実際の型とオプティマイザがどれだけできるかによって異なります。ただし、単純なユーザー タイプを除くすべての場合、オプティマイザーはデフォルト コンストラクターに副作用があると想定しなければならない場合があるため、単純に削除することはできません。

コストはデフォルトのコンストラクターにあるため、この追加コストはユーザー型にのみ適用する必要があります。int のようなプリミティブ型、または実際には自明なコンストラクター/コピーを持つすべてのプリミティブ型の場合、デフォルトのコンストラクターにはコストがかかりません。データは単純に初期化されません (関数スコープにある場合)。

于 2012-01-18T17:31:44.270 に答える
0

これにより、潜在的なパフォーマンスが向上するのはなぜですか?

最初のケースでは、デフォルトの初期化が行われ、その後に代入が続きます。2 つ目は、値からの初期化を伴います。デフォルトの初期化は、割り当てによって後でやり直す (または元に戻す) 必要がある作業を行う可能性があるため、最初のケースは 2 番目のケースよりも多くの作業を伴う可能性があります。

ユーザー定義型 (または STL 型でさえ) だけですか、それとも int、float などにも当てはまりますか?

ユーザー定義型の場合のみです。そして、コンストラクターと代入演算子が実際に何をするかによって異なります。スカラー型の場合、デフォルトの初期化は何もせず、代入は値からの初期化と同じことを行うため、どちらの選択肢も同等になります。

于 2012-01-18T17:37:25.320 に答える
-1

このクラスには、文字列を初期化する 3 つの方法があります。

string  s;         // Default constructor
string  s = "..."; // Default constructor followed by operator assignment
string  s("...");  // Constructor with parameters passed in

文字列クラスはメモリを割り当てる必要があります。必要なメモリ量がわかったら、割り当てることをお勧めします。

于 2012-01-18T17:30:54.910 に答える