質問

なぜ++i l値i++ありませんか?

役に立ちましたか?

解決

きっかけとして、answerer指摘されている理由 ++i はlvalueはパスで参照しています。

int v = 0;
int const & rcv = ++v; // would work if ++v is an rvalue too
int & rv = ++v; // would not work if ++v is an rvalue

その理由のためのルールは、初期化の参照を文字通りの際の参考定数:

void taking_refc(int const& v);
taking_refc(10); // valid, 10 is an rvalue though!

なぜ紹介しrvalueでお気軽にご相談ください.でも、これらの条件がビルの言語の規則はこれらの状況にどのように対処する:

  • 私たちも背筋が伸びる思いでしたロケータ値とします。うる値が含まれていると読み取ることができます。
  • い表現の値表現です。

以上の二点から、C99の標準を含むこの素敵な脚注に非常に役に立:

【名"lvalue"に来 からの割り当て表現E1= E2は、左側のオペランドはE1 ることが求められます(変更可能)lvalue.た方が良いかもしれる を表すオブジェクト"ロケータ 付加価値"です。何とも呼ばれる "rvalue"は、この国際 基準において、"価値の する詳細情報がご覧いただけます]

ロケータ値という lvalue, の値による評価とその位置にあるという rvalue.この権利によるものC++の標準の話をlvalueにrvalue換算):

4.1/2:の価値に含まれるオブジェクト で示されるlvalueのrvalue 結果です。

結論

上記の意味で今だに i++ なlvalueがrvalue.での発現が返されないに位置し i もうで増加!), での値です。変更が返された値 i++ のような感覚で、どのような人が住んでいますかかいが読み取れる値です。を基準とでrvalue、このようにのみ結合の参考にconst.

しかし、constrastの表現で返される ++i の位置(lvalue) i.挑発するlvalueにrvalue変換のように int a = ++i; す数値を読取ったことと思います。また、作るを参考にしながるので、読み出しの値以降: int &a = ++i;.

注またどrvaluesが生成されます。例えば、すべてのtemporariesはrvaluesのバイナリ/単項+、マイナスとすべての戻り値のないような表現を参照です。すべての表現は、指定されたオブジェクトが行な価値だけます。ている場合は、それらの数値でのバックアップを取ることによりオブジェクトを一定というわけではありません。

次のC++のバージョンが含まれ rvalue references ともポイントnonconstで結合したrvalue.の根拠できるのが"盗"離れの資源からの匿名物を避けて、コピーやっています。を想定したクラスタが過負荷の接頭辞++(帰国 Object& やpostfix++(帰国 Objectによる下を起こしコピーし、次の場合で盗の資源からのrvalue:

Object o1(++a); // lvalue => can't steal. It will deep copy.
Object o2(a++); // rvalue => steal resources (like just swapping pointers)

他のヒント

他の人がポストとプレインクリメント間の機能の違いに取り組んできています。

限りあるとしての左辺値の懸念している、i++は、変数を参照しないために割り当てることができません。これは、計算された値を意味する。

の割り当ての観点からは、次の両方の方法と同じ種類で意味をなさないます:

i++   = 5;
i + 0 = 5;
事前増分がインクリメントされた変数への参照ではなく、一時的なコピーを返すので、

++iは左辺値です。

あなたも良いもう少しヘビー級int型よりも(例えばSTL中)イテレータオブジェクトのようなものをインクリメントしているとき、

パフォーマンス上の理由から、事前増分を好むことは特に良いアイデアになります。

ように思われる方が多くいると思うので行うことを説明する ++i はlvalueではなく、 なぜ, として、 なぜ たはC++の基準委員会はこの特徴は、特にこのCることがないとしてもlvalues.から この議論のcomp.std.c++, これすることができますので、そのアドレスまたは割り当てを参照しています。コードサンプル抜粋からキリスト教のベイルート-アラブ大学のポスト:

   int i;
   extern void f (int* p);
   extern void g (int& p);

   f (&++i);   /* Would be illegal C, but C programmers
                  havent missed this feature */
   g (++i);    /* C++ programmers would like this to be legal */
   g (i++);    /* Not legal C++, and it would be difficult to
                  give this meaningful semantics */

の方の場合 i が内蔵タイプ、課題な ++i = 10 呼び出し 未定義の動作, ので、 i 変更された二の間の配列をポイント。

私がコンパイルしようとすると、

私は左辺値のエラーを取得しています。

i++ = 2;

ではなく、私はそれを変更した場合、

++i = 2;

接頭演算子は(++ I)は、iの値を変更するので、これは、次いで、iが返されるので、依然としてに割り当てることができます。代入演算子により変更することはできません後置演算子(私は++)は、iの値を変更しますが、古いの値のの一時コピーを返します。

<時間>

元の質問への回答

あなたが自分で文でインクリメント演算子を使用して話をしている場合は、

、forループのように、それは実際に違いはありません。前置インクリメントがポストインクリメント自体をインクリメントし、一時的な値を返すことがあるため、より効率的なように見えますが、コンパイラは離れてこの違いを最適化します。

for(int i=0; i<limit; i++)
...

と同一であります
for(int i=0; i<limit; ++i)
...
あなたは、より大きな文の一部として操作の戻り値を使用しているとき、

物事はもう少し複雑になります。

でも、2つの簡単な文

int i = 0;
int a = i++;

int i = 0;
int a = ++i;

は異なっています。あなたはマルチオペレータ文の一部として使用することを選択し、操作者が意図した動作が何であるかに依存してインクリメントどの。要するに、ないあなただけのいずれかを選択することはできません。あなたは両方を理解する必要があります。

PODプリインクリメント:

前の増分は、オブジェクトが式の前に増分されたかのように機能し、それが起こったかのように、この式の中で使用可能であるべきです。したがってC ++標準comiteeは、L値としても使用することができることを決定した。

PODポストインクリメント:

ポストインクリメントは(n2521セクション5.2.6を参照してください)PODオブジェクトをインクリメントし、発現に使用するためにコピーを返す必要があります。コピーとして実際にはL値が任意の意味をなさない作る変数ではありません。

オブジェクト:

のオブジェクトの前と後の増分は、言語だけの構文糖は、オブジェクトのメソッドを呼び出すための手段を提供しています。したがって、技術的にはオブジェクトは、言語の標準的な動作ではなく、唯一のメソッド呼び出しによる制約によって制限されていません。

これは、(それが必要ですが、期待されていない)PODオブジェクトの振る舞いを反映し、これらのオブジェクトの振る舞いをするために、これらのメソッドの実装に任されています。

オブジェクトプリインクリメント:

要件(期待される動作は)ここで、オブジェクトがインクリメント(オブジェクト依存の意味)と方法が変更され、増分が起こった後に増分が、この前に起こったかのように(元のオブジェクトのように見えるの値を返すことです声明)。

これを行うにはsipleで、メソッドは自己への参照を返すことだけが必要です。参照は、L値であるため、期待通りに動作します。

ポストインクリメントオブジェクト

要件(期待される動作は)ここで、オブジェクトが(プリインクリメントと同じように)インクリメントされていることで、値が古い値のようなルックスを返され、それがLのように動作しないように(非可変です - 値)。

非変更可能な:あなたがオブジェクトを返す必要がありますこれを行うに
。オブジェクトは、式の中で使用されている場合、それは一時的な変数に構築コピーとなります。一時的な変数は、constのであり、したがって、それは非可変し、期待どおりに動作します。

は、古い値のようになります。これは、単に任意の変更をmakeing前に(おそらくコピーコンストラクタを使用して)オリジナルのコピーを作成することによって達成される
。コピーは、そうでない場合は、元に変更はコピーに影響を与えますので、状態は、オブジェクトを用いた発現との関係に変化します深いコピーする必要があります。

前の増分と同じように:それはあなたが同じ動作を取得するように、プリインクリメントの面でポストインクリメントを実装するためにおそらく最高です

class Node // Simple Example
{
     /*
      * Pre-Increment:
      * To make the result non-mutable return an object
      */
     Node operator++(int)
     {
         Node result(*this);   // Make a copy
         operator++();         // Define Post increment in terms of Pre-Increment

         return result;        // return the copy (which looks like the original)
     }

     /*
      * Post-Increment:
      * To make the result an l-value return a reference to this object
      */
     Node& operator++()
     {
         /*
          * Update the state appropriatetly */
         return *this;
     }
};

に関するLValue

  • C (Perlス ++ii++ はLValues.

  • C++, i++ はないとLValueが ++i です。

    ++i に相当 i += 1, 相当する i = i + 1.
    その結果、まだ扱うオブジェクトと同じオブジェクト i.
    もとも捉えることが可能である:

    int i = 0;
    ++i = 3;  
    // is understood as
    i = i + 1;  // i now equals 1
    i = 3;
    

    i++ 一方で閲覧される可能性があります。て
    最初に利用してい i, その追加モードの場合は、ファイ オブジェクト i.

    int i = 0;
    i++ = 3;  
    // would be understood as 
    0 = 3  // Wrong!
    i = i + 1;
    

(編集:更新後のblotched初の試み).

主な違いは、私はポストインクリメント値を返し++に対し、iは++プリインクリメント値を返すことです。私は本当に<全角>場合、すなわちは、プリインクリメント値を必要とします。

- 私は++を使用することは非常に説得力のある理由がない限り、私は通常、私は++を使用します。

私見「++ I」のフォームを使用することをお勧めします。あなたは整数または他のPODを比較したときに前後のインクリメントとの違いは実際に測定可能ではありませんが、別の目的は、あなたが作ると使用する際返す必要がコピー「私を++」オブジェクトは非常に高価いずれかである場合には、パフォーマンスに大きな影響を与えることを表すことができますコピー、または頻繁にインクリメントします。

ところで - 同じ文の中で同じ変数に複数のインクリメント演算子を使用しないでください。あなたはと操作の未定義のため、少なくともC.に私はそれの一部はJava ND C#でクリーンアップされたと思いますが、「どこシーケンスポイントがある」。

の混乱に入ります

たぶん、あなた方のインクリメントを実装します。このようなこと:

  • コピーを作成し、元の値メモリ
  • 増分の変動
  • のコピー

以降のコピーがでない変数でも参考に動的に割り当てられたメモリではできないのl値です。

How does the compiler translate this expression? a++

We know that we want to return the unincremented version of a, the old version of a before the increment. We also want to increment a as a side effect. In other words, we are returning the old version of a, which no longer represents the current state of a, it no longer is the variable itself.

The value which is returned is a copy of a which is placed into a register. Then the variable is incremented. So here you are not returning the variable itself, but you are returning a copy which is a separate entity! This copy is temporarily stored inside a register and then it is returned. Recall that a lvalue in C++ is an object that has an identifiable location in memory. But the copy is stored inside a register in the CPU, not in memory. All rvalues are objects which do not have an identifiable location in memory. That explains why the copy of the old version of a is an rvalue, because it gets temporarily stored in a register. In general, any copies, temporary values, or the results of long expressions like (5 + a) * b are stored in registers, and then they are assigned into the variable, which is a lvalue.

The postfix operator must store the original value into a register so that it can return the unincremented value as its result. Consider the following code:

for (int i = 0; i != 5; i++) {...}

This for-loop counts up to five, but i++ is the most interesting part. It is actually two instructions in 1. First we have to move the old value of i into the register, then we increment i. In pseudo-assembly code:

mov i, eax
inc i

eax register now contains the old version of i as a copy. If the variable i resides in the main memory, it might take the CPU a lot of time to go and get the copy all the way from the main memory and move it into the register. That is usually very fast for modern computer systems, but if your for-loop iterates a hundred thousand times, all those extra operations start to add up! It would be a significant performance penalty.

Modern compilers are usually smart enough to optimize away this extra work for integer and pointer types. For more complicated iterator types, or maybe class types, this extra work potentially might be more costly.

What about the prefix increment ++a?

We want to return the incremented version of a, the new version of a after the increment. The new version of a represents the current state of a, because it is the variable itself.

First a is incremented. Since we want to get the updated version of a, why not just return the variable a itself? We do not need to make a temporary copy into the register to generate an rvalue. That would require unnecessary extra work. So we just return the variable itself as an lvalue.

If we don't need the unincremented value, there's no need for the extra work of copying the old version of a into a register, which is done by the postfix operator. That is why you should only use a++ if you really need to return the unincremented value. For all other purposes, just use ++a. By habitually using the prefix versions, we do not have to worry about whether the performance difference matters.

Another advantage of using ++a is that it expresses the intent of the program more directly: I just want to increment a! However, when I see a++ in someone else's code, I wonder why do they want to return the old value? What is it for?

C#:

public void test(int n)
{
  Console.WriteLine(n++);
  Console.WriteLine(++n);
}

/* Output:
n
n+2
*/
ライセンス: CC-BY-SA帰属
所属していません StackOverflow
scroll top