例: 2 つの番号を交換する単純なプログラム。
int a = 10;
int b = 20;
a = a+b;
b = a-b;
a = a-b;
次のコードで:
a=a+b-(b=a);
つまり、これら 2 つのコードの違いは何ですか?
追加 : これら 2 つの追加が、Java と C++ の場合とは異なる整数の正当な制限を超えた場合はどうなりますか?
これらはどちらも私には良く見えません。読みやすさが鍵です。値を交換したい場合、最も「明白な」方法は、一時的な値を使用することです。
int a = 10;
int b = 20;
int tmp = a;
a = b;
b = tmp;
これが算術を含む「賢い」アプローチと同じくらい効率的であったかどうかは、私にはわかりませんし、気にすることもありません。パフォーマンスの違いが実際のアプリケーション内で重要であることを誰かが証明するまで、機能する最も単純なコードを目指します。ここだけでなく、すべてのコードに対して。どの程度のパフォーマンスが必要か (およびどの次元で) を決定し、テストし、必要に応じてより複雑で効率的なものに変更します。
(もちろん、swap
プラットフォーム内で利用可能な操作がある場合は、代わりにそれを使用してください...さらに明確です。)
a+b-(b=a)
C++ では、シーケンス ポイントがなく、そこから変更b
して読み取るため、コードは未定義の動作を引き起こします。
を使用しstd::swap(a,b)
たほうがよいでしょう。速度が最適化されており、そこにあるものよりもはるかに読みやすくなっています。
あなたの特定のコードはすでにコメントされているので、一般的な側面を追加します。命令レベルでは、アセンブリが機械語に変換されるステップ数を逃れることができないため、ライナーを 1 つ書くことは実際には問題ではありません。ほとんどのコンパイラは、すでにそれに応じて最適化しています。
つまり、1 つのライナーが実際に目標を達成するために別のメカニズムを使用していない限り、たとえば 2 つの変数を交換する場合、3 番目の変数を使用せず、型オーバーフローなどのすべてのハードルを回避し、ビット単位の演算子を使用できる場合を除きます。たとえば、1 つのメモリ ロケーションを保存して、そのロケーションにアクセスしたとします。
実際には、これはほとんど価値がなく、他の回答で既に述べたように読みやすさの問題です。専門的なプログラムは、人々によって維持される必要があるため、理解しやすいものでなければなりません。
優れたコードの 1 つの定義は、コードが実際に実行しているように見えることです。
あなた自身でさえ、短縮された複雑な操作に関して巧妙に記述されている場合、独自のコードを修正するのは難しいと感じるでしょう。読みやすさは常に優先されるべきであり、ほとんどの場合、実際に必要な効率は、短いワンライナーではなく、設計、アプローチ、またはより優れたデータ構造/アルゴリズムの改善から得られます。
Dijkstraの引用:有能なプログラマーは、自分の頭蓋骨のサイズが限られていることを十分に認識しています。したがって、彼は完全に謙虚に自分の仕事に取り組み、ペストのような巧妙なトリックを避けます.
いくつかのポイント:
この点で、最も説明的で直感的で最速のコードは次のとおりです。
std::swap(a, b);
コードを書いたり読んだりするときに、読みやすさとすぐに理解できることは、私が個人的に評価するものです (そして他の何人かが投票するかもしれません)。メンテナンス性が向上します。提供された特定の例では、作成者がこれらの数行で何を達成しようとしているのかをすぐに理解することは困難です。1 行のコード:a=a+b-(b=a);
非常に巧妙ですが、作成者の意図が他の人に明らかに伝わりません。
効率の面では、コンパイラによる最適化はとにかくそれを達成します。
少なくともJavaに関しては、JVMは通常の単純な使用に最適化されていることを読んだことを覚えています。そのようなことをしようとすると、自分をだますことがよくあります。
しかも見た目がひどい。
OK、これを試してください。次回奇妙なバグが発生した場合は、できるだけ多くのコードを 1 行にまとめることから始めます。
数週間待って、それがどのように機能するかを忘れてしまった.
デバッグしてみてください。
もちろん、それはコンパイラに依存します。私はどんな種類の驚くべき違いも予見できませんが. 難解なコードがメインです。