web-dev-qa-db-ja.com

C ++でのインクリメント-x ++または++ xを使用する場合

私は現在C++を学んでおり、少し前に増分について学習しました。 「++ x」を使用して前に増分を行い、「x ++」を使用してその後に増分できることを知っています。

それでも、私は2つのうちのどちらをいつ使用すべきか本当にわからない...私は実際に「++ x」を使用したことはなく、これまでは常に正常に機能していました。

例:forループで、「++ x」を使用することが望ましい場合

また、誰かが異なる増分(または減分)がどのように機能するかを正確に説明できますか?とても感謝しております。

80
Jesse Emond

それは好みの問題ではなく、論理の問題です。

x++は変数xの値を増分します-現在のステートメントを処理します。

++xは変数xの値をインクリメントします-before現在のステートメントを処理します。

したがって、作成するロジックを決定するだけです。

x += ++iはiをインクリメントし、xにi + 1を追加します。 x += i++はiをxに追加し、iをインクリメントします。

98

Scott Meyers は、接尾辞が適切であるとロジックが決定する場合を除き、プレフィックスを優先するように指示します。

"More Effective C++" item#6 -それは私にとって十分な権限です。

本を所有していない人のために、ここに適切な引用があります。 32ページから:

Cプログラマーとしての日々から、インクリメント演算子のプレフィックス形式は「インクリメントとフェッチ」と呼ばれることがありますが、ポストフィックス形式は「フェッチとインクリメント」と呼ばれることが多いことを思い出してください。 2つのフレーズは覚えておくことが重要です。なぜなら、それらはすべて正式な仕様として機能する以外は...

そして34ページ:

あなたが効率性を心配するような人なら、おそらく後置インクリメント機能を見たときに汗をかいたでしょう。この関数は、戻り値用の一時オブジェクトを作成する必要があり、上記の実装は、構築および破棄する必要がある明示的な一時オブジェクトも作成します。プレフィックスインクリメント関数にはそのような一時的なものはありません...

45
duffymo

cppreference 反復子をインクリメントする場合:

古い値を使用しない場合は、プリインクリメント演算子(++ iter)をポストインクリメント演算子(iter ++)より優先する必要があります。ポストインクリメントは一般的に次のように実装されます:

   Iter operator++(int)   {
     Iter tmp(*this); // store the old value in a temporary object
     ++*this;         // call pre-increment
     return tmp;      // return the old value   }

明らかに、プリインクリメントよりも効率的ではありません。

事前インクリメントは、一時オブジェクトを生成しません。オブジェクトの作成に費用がかかる場合、これは大きな違いになります。

20
Phillip Ngan

セマンティック(プリ/ポストの)が重要ではないプリ/ポストインクリメントを使用する場合、生成されたコードは同じであることに注意してください。

例:

pre.cpp:

#include <iostream>

int main()
{
  int i = 13;
  i++;
  for (; i < 42; i++)
    {
      std::cout << i << std::endl;
    }
}

post.cpp:

#include <iostream>

int main()
{

  int i = 13;
  ++i;
  for (; i < 42; ++i)
    {
      std::cout << i << std::endl;
    }
}

_

$> g++ -S pre.cpp
$> g++ -S post.cpp
$> diff pre.s post.s   
1c1
<   .file   "pre.cpp"
---
>   .file   "post.cpp"
7
chub

覚えておくべき最も重要なことは、imo、x ++は実際にインクリメントが行われる前に値を返す必要があるということです。したがって、オブジェクトの一時的なコピーを作成する必要があります(インクリメント前)。これは、インプレースでインクリメントされて返される++ xよりも効率的ではありません。

ただし、言及する価値のあるもう1つのことは、ほとんどのコンパイラーが、可能な場合にそのような不要なものを最適化できることです。たとえば、両方のオプションが同じコードになります。

for (int i(0);i<10;++i)
for (int i(0);i<10;i++)
6
rmn

@BeowulfOFに同意しますが、明確にするために、論理が完全に明確になるように、ステートメントを分割することを常に推奨します。

i++;
x += i;

または

x += i;
i++;

だから私の答えは、あなたが明確なコードを書いているなら、これはめったに重要ではないだろう(そして、それが重要なら、あなたのコードはおそらく十分に明確ではない)。

2
Bids

++ xはx ++よりもfasterであると予想されることを強調したいだけです(特にxが任意の型のオブジェクトの場合)。したがって、論理的な理由で必要でない限り、++ xは中古。

2
Shailesh Kumar

違いを正しく説明しました。ループを実行するたびに、またはその後にxを増分するかどうかに依存します。それはあなたのプログラムのロジック、適切なものに依存します。

STLイテレータ(これらの演算子も実装します)を扱う際の重要な違いは、it ++がイテレータが指すオブジェクトのコピーを作成し、増分してからコピーを返すことです。一方、++ itは最初にインクリメントを実行してから、反復子が指すオブジェクトへの参照を返します。これは、パフォーマンスのあらゆる部分が重要な場合や、独自のSTLイテレータを実装する場合にほとんど関係します。

編集:プレフィックス表記とサフィックス表記の混同を修正

1
Björn Pollex

後置形式の++、-演算子はルールに従いますse-then-change

プレフィックス形式(++ x、-x)は、ルールchange-then-useに従います。

例1:

coutを使用して複数の値を<<でカスケードすると、計算(ある場合)は右から左に行われますが、印刷は左から-右例、(ifval最初は10)

 cout<< ++val<<" "<< val++<<" "<< val;

になります

12    10    10 

例2:

Turbo C++では、式で++または(任意の形式で)の複数の出現が見つかった場合、最初にすべての接頭辞形式が計算され、次に式が評価され、最後に接尾辞形式が計算されます。

int a=10,b;
b=a++ + ++a + ++a + a;
cout<<b<<a<<endl;

Turbo C++での出力は次のようになります。

48 13

一方、現代のコンパイラでの出力は(厳密に規則に従うため)

45 13
  • 注:1つの式で同じ変数に増分/減分演算子を複数使用することはお勧めしません。そのような取り扱い/結果
    式はコンパイラごとに異なります。
0
Sunil Dhillon

コードの明瞭さを考慮するときは、言語構文を理解することが重要です。たとえば、ポストインクリメントを使用して、文字列をコピーすることを検討してください。

char a[256] = "Hello world!";
char b[256];
int i = 0;
do {
  b[i] = a[i];
} while (a[i++]);

文字列の最後にゼロ文字(falseをテスト)が検出されるまでループを実行する必要があります。それには、値の事前インクリメントのテストと、インデックスのインクリメントが必要です。しかし、必ずしもその順序ではありません-事前インクリメントでこれをコーディングする方法は次のとおりです。

int i = -1;
do {
  ++i;
  b[i] = a[i];
} while (a[i]);

それはより明確な好みの問題であり、マシンがレジスタのハンドフルを持っている場合、たとえa [i]が高価な関数または副作用を持つ関数であっても、両方とも同じ実行時間を持たなければなりません。大きな違いは、インデックスの終了値です。

0
shkeyser