2016-02-10 9 views
5

まず例この2つの値の参照例が異なる動作をするのはなぜですか?

int a = 0; 
auto && b = ++a; 
++a; 
cout << a << b << endl; 

プリント22

第二の例

int a = 0; 
auto && b = a++; 
++a; 
cout << a << b << endl; 

プリント20

質問: なぜ最初の例で++aの3行目もbをインクリメントし、2番目の例でそのような動作がないのはなぜですか?

更新:New questionが発生しました。

+0

私はあなたにヒントを与えます - 'a'はrvalueではありません。 – erip

+0

@eripはい、私は知っていますが、 'b'の2つの例の違いは何ですか? – vladon

+0

2番目の例では、 'b'は、最初の例のように、前にインクリメントせずに' a'の値を取得します。 – x13

答えて

10

プリインクリメント(++a)ので、最初aへの参照を返す次いで、aの値をインクリメントし、結果を格納し、。今すぐabは、効果的に同じオブジェクトを指します。

しかしポストインクリメント(a++)、最初は一時的な、増分aaの現在値、およびこの一時を返す - そのあなたの右辺値REFポイントに。 abは異なるオブジェクトを指しています。具体的にはbは、インクリメントする前に値aを一時的に保持しています。

イテレータとインクリメント/デクリメントを定義する他の複雑なオブジェクトのためのit++++itを使用することをお勧めします理由です:後者は一時的なコピーを作成し、これ遅くなることがあります。

+0

2番目の例で 'a ++ 'の後に' b'を使用するのはUBですか? – vladon

+0

そして、なぜ最初のケースでは一時的なものはありませんか?なぜ 'auto && b = a ++'は 'auto && b = a;と同じではないのですか? a ++ '? – vladon

+0

@vladon:一時的なものは、それがUBではないことを意味するスコープから外れるまで生き延びるだろうと思っていますが、わかりません。 –

1

2番目のケース(ポストインクリメント)では、bは実際に(a ++)用に作成されたテンポラリを参照するため、増分はbに影響しません。

2

++aは左辺値ですが、a++ではありません。これは、C++ 14 [expr.pre.incr]/1で指定される:

プレフィックス++のオペランドは、1を加えることによって修飾されている[...] オペランドは変更左辺値でなければなりません。 [...]結果は更新されたオペランドです。それは左辺値

で、[expr.post.incr]/1:

[...]結果はprvalueです。


今、私たちはauto && b = ++a;を考えます。 ++aは左辺値です。 auto&&は転送参照です。転送参照は実際にはlvaluesにバインドできます。auto自体が参照型に推定される可能性があります。このコードはint &b = ++a;と推測しています。

参照が同じ型の左辺値にバインドされている場合、参照が直接バインドされるため、baの別の名前になります。


第2の例では

auto && b = a++;a++ prvalueあります。つまり、関連付けられたアドレスがなく、変数aとの関係はなくなりました。この行は、++a; auto && b = (a + 0);と同じ動作をします。

まず、a++は正価であるため、auto&&int&&になります。 (すなわちautointになります)。非クラス型の参照がprvalueにバインドされると、一時オブジェクトは値からコピー初期化されます。このオブジェクトは、参照と一致するように拡張された存続期間を持ちます。第2のケースでそうb

aから別のオブジェクトにバインドされ、(それは限りbがするように持続するので、本当に一時的ではありません)「一時的」int型。

参照バインディングルールは[dcl.init.ref]にあります。

関連する問題