85

I was reading Stroustrup's "The C++ Programming Language", where he says that out of two ways to add something to a variable

x = x + a;

and

x += a;

He prefers += because it is most likely better implemented. I think he means that it works faster too.
But does it really? If it depends on the compiler and other things, how do I check?

4

11 に答える 11

215

そのソルトに値するコンパイラーは、ステートメントが本当に単純であり、最適化が有効になっている限り、組み込み型 ( 、など)intの両方の構造に対してまったく同じ機械語シーケンスを生成します。(特に、デフォルト モードであるGCCは、デバッガーが常に変数値を見つけられるようにするために、完全に不要なストアをメモリに挿入するなどのアンチ最適化を実行します。)floatx = x + a; -O0

ただし、ステートメントがより複雑な場合は、異なる場合があります。fがポインタを返す関数であると仮定すると、

*f() += a;

呼び出しfは 1 回だけですが、

*f() = *f() + a;

2回呼び出します。f副作用がある場合、2 つのうちの 1 つが間違っています (おそらく後者)。f副作用がない場合でも、コンパイラは 2 番目の呼び出しを排除できない可能性があるため、後者は確かに遅くなる可能性があります。

ここでは C++ について話しているので、 と をオーバーロードするクラス型の場合は状況がまったく異なりoperator+ますoperator+=。がそのようなタイプの場合x、 -- 最適化前 -- にx += a変換されます

x.operator+=(a);

一方、x = x + aに変換します

auto TEMP(x.operator+(a));
x.operator=(TEMP);

さて、クラスが適切に書かれコンパイラのオプティマイザが十分に優れていれば、どちらも同じ機械語を生成することになりますが、組み込み型の場合のように確実ではありません。これはおそらく、Stroustrup が の使用を奨励するときに考えていることです+=

于 2012-09-18T15:00:35.733 に答える
57

You can check by looking at the dissasembly, which will be the same.

For basic types, both are equally fast.

This is output generated by a debug build (i.e. no optimizations):

    a += x;
010813BC  mov         eax,dword ptr [a]  
010813BF  add         eax,dword ptr [x]  
010813C2  mov         dword ptr [a],eax  
    a = a + x;
010813C5  mov         eax,dword ptr [a]  
010813C8  add         eax,dword ptr [x]  
010813CB  mov         dword ptr [a],eax  

For user-defined types, where you can overload operator + and operator +=, it depends on their respective implementations.

于 2012-09-18T14:50:58.587 に答える
10

はい!書くのも読むのも速く理解するのも早いxです。そのため、全体的に人間の方が高速です。一般的に、人間の時間はコンピューターの時間よりもはるかにコストがかかるため、それがあなたが求めていたものであるに違いありません. 右?

于 2012-09-19T03:48:05.127 に答える
9

x = x + aとの違いx += aは、マシンが実行しなければならない作業の量です。一部のコンパイラは、最適化を除外する場合があります (通常は実行します)。ただし、通常、最適化をしばらく無視すると、前者のコード スニペットでは、マシンは値をx2 回検索する必要がありますが、後者の場合、この検索は 1 回だけ行う必要があります。

ただし、前述したように、今日のほとんどのコンパイラは、命令を分析し、結果として必要なマシン命令を削減するのに十分なほどインテリジェントです。

PS: スタック オーバーフローに関する最初の回答です。

于 2012-09-18T18:09:39.853 に答える
8

これは、x と a の型と + の実装に大きく依存します。為に

   T x, a;
   ....
   x = x + a;

コンパイラは、x + a の値を含む一時的な T を作成し、それを評価する必要があります。これを x に割り当てることができます。(この操作中に x または a をワークスペースとして使用することはできません)。

x += a の場合、テンポラリは必要ありません。

自明なタイプの場合、違いはありません。

于 2012-09-18T14:56:09.823 に答える
7

+=あなたがコンパイラの生活をずっと楽にしていると言ったら。x = x+aが と同じであることをコンパイラが認識するために、コンパイラは次のことを行う必要がx += aあります。

  • 左辺 ( x) を分析して、副作用がなく、常に同じ左辺値を参照していることを確認します。たとえば、 である可能性がありz[i]、 と の両方が変更されないようにする必要がzありiます。

  • 右辺 ( x+a) を分析し、それが和であること、および左辺が右辺で 1 回だけ発生することを確認してz[i] = a + *(z+2*0+i)ください。

に追加することを意味する場合axコンパイラの作成者は、あなたが意味することを言うだけでそれを高く評価します。そうすれば、作者がすべてのバグを取り除くことを望んでいるコンパイラの部分を実行することはありません。正直に頭を悩ませることができない場合を除いて、実際には人生を楽にすることはありません。 Fortran モードの。

于 2012-09-18T18:57:02.117 に答える
6

この C++ にラベルを付けたので、投稿した 2 つのステートメントから知る方法はありません。「x」が何であるかを知る必要があります (答えの「42」に少し似ています)。がPODの場合x、実際には大きな違いはありません。ただし、xがクラスの場合、operator +およびoperator +=メソッドのオーバーロードが存在する可能性があり、これらの動作が異なるため、実行時間が大きく異なる可能性があります。

于 2012-09-18T14:56:04.743 に答える
5

具体的な例として、単純な複素数型を想像してください。

struct complex {
    double x, y;
    complex(double _x, double _y) : x(_x), y(_y) { }
    complex& operator +=(const complex& b) {
        x += b.x;
        y += b.y;
        return *this;
    }
    complex operator +(const complex& b) {
        complex result(x+b.x, y+b.y);
        return result;
    }
    /* trivial assignment operator */
}

a = a + b の場合、追加の一時変数を作成してからコピーする必要があります。

于 2012-09-18T19:52:28.470 に答える
5

あなたは間違った質問をしています。

これにより、アプリや機能のパフォーマンスが向上することはまずありません。たとえそうであったとしても、それを見つける方法は、コードをプロファイリングし、それがどのようにあなたに影響を与えるかを確実に知ることです. このレベルでどちらが速いかを心配するよりも、明快さ、正確さ、読みやすさの観点から考えることがはるかに重要です。

これは、これが重要なパフォーマンス要因であっても、コンパイラが時間とともに進化することを考えると特に当てはまります。誰かが新しい最適化を見つけ出し、今日の正しい答えが明日には間違っている可能性があります。これは時期尚早の最適化の典型的なケースです。

これは、パフォーマンスがまったく問題ではないということではありません...パフォーマンスの目標を達成するためのアプローチが間違っているというだけです。適切なアプローチは、プロファイリング ツールを使用して、コードが実際にどこで時間を費やしているか、つまりどこに労力を集中すべきかを知ることです。

于 2012-09-18T18:35:53.313 に答える
4

それはマシンとそのアーキテクチャに依存するべきだと思います。アーキテクチャが間接的なメモリ アドレッシングを許可している場合、コンパイラの作成者は代わりにこのコードを (最適化のために) 使用する可能性があります。

mov $[y],$ACC

iadd $ACC, $[i] ; i += y. WHICH MIGHT ALSO STORE IT INTO "i"

一方、i = i + y(最適化なしで)次のように変換される可能性があります。

mov $[i],$ACC

mov $[y],$B 

iadd $ACC,$B

mov $B,[i]


とは言っても、 ifiがポインタを返す関数であるなどの他の複雑さも考慮する必要があります。GCC を含むほとんどの製品レベルのコンパイラは、両方のステートメントに対して同じコードを生成します (整数の場合)。

于 2012-09-18T19:30:49.123 に答える
2

いいえ、どちらの方法も同じように処理されます。

于 2012-09-18T14:52:22.753 に答える