post-increment - override++ operator




Diferença entre i++ e++ i em um loop? (14)

Existe uma diferença em ++i e i++ em um loop for ? É simplesmente uma coisa sintaxe?


A questão é:

Existe uma diferença em ++ i e i ++ em um loop for?

A resposta é: não .

Por que todas as outras respostas têm que entrar em explicações detalhadas sobre pré e pós-incremento quando isso não é solicitado?

Este for-loop:

for (int i = 0; // Initialization
     i < 5;     // Condition
     i++)       // Increment
{
   Output(i);
}

Seria traduzir para este código sem usar loops:

int i = 0; // Initialization

loopStart:
if (i < 5) // Condition
{
   Output(i);

   i++ or ++i; // Increment

   goto loopStart;
}

Agora importa se você coloca i++ ou ++i como incremento aqui? Não, não, como o valor de retorno da operação de incremento é insignificante. i serei incrementado APÓS a execução do código que está dentro do corpo do loop for.


Ambos aumentam o número. ++i é equivalente a i = i + 1 .

i++ e ++i são muito parecidos, mas não exatamente iguais. Ambos incrementam o número, mas ++i incrementa o número antes que a expressão atual seja avaliada, enquanto i++ incrementa o número após a expressão ser avaliada.

int i = 3;
int a = i++; // a = 3, i = 4
int b = ++a; // b = 4, a = 

Verifique este link .


Como esse código mostra (consulte o MSIL dissambled nos comentários), o compilador C # 3 não faz distinção entre i ++ e ++ i em um loop for. Se o valor de i ++ ou ++ i estivesse sendo obtido, definitivamente haveria uma diferença (isso foi compilado no Visutal Studio 2008 / Release Build):

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace PreOrPostIncrement
{
    class Program
    {
        static int SomethingToIncrement;

        static void Main(string[] args)
        {
            PreIncrement(1000);
            PostIncrement(1000);
            Console.WriteLine("SomethingToIncrement={0}", SomethingToIncrement);
        }

        static void PreIncrement(int count)
        {
            /*
            .method private hidebysig static void  PreIncrement(int32 count) cil managed
            {
              // Code size       25 (0x19)
              .maxstack  2
              .locals init ([0] int32 i)
              IL_0000:  ldc.i4.0
              IL_0001:  stloc.0
              IL_0002:  br.s       IL_0014
              IL_0004:  ldsfld     int32 PreOrPostIncrement.Program::SomethingToIncrement
              IL_0009:  ldc.i4.1
              IL_000a:  add
              IL_000b:  stsfld     int32 PreOrPostIncrement.Program::SomethingToIncrement
              IL_0010:  ldloc.0
              IL_0011:  ldc.i4.1
              IL_0012:  add
              IL_0013:  stloc.0
              IL_0014:  ldloc.0
              IL_0015:  ldarg.0
              IL_0016:  blt.s      IL_0004
              IL_0018:  ret
            } // end of method Program::PreIncrement             
             */
            for (int i = 0; i < count; ++i)
            {
                ++SomethingToIncrement;
            }
        }

        static void PostIncrement(int count)
        {
            /*
                .method private hidebysig static void  PostIncrement(int32 count) cil managed
                {
                  // Code size       25 (0x19)
                  .maxstack  2
                  .locals init ([0] int32 i)
                  IL_0000:  ldc.i4.0
                  IL_0001:  stloc.0
                  IL_0002:  br.s       IL_0014
                  IL_0004:  ldsfld     int32 PreOrPostIncrement.Program::SomethingToIncrement
                  IL_0009:  ldc.i4.1
                  IL_000a:  add
                  IL_000b:  stsfld     int32 PreOrPostIncrement.Program::SomethingToIncrement
                  IL_0010:  ldloc.0
                  IL_0011:  ldc.i4.1
                  IL_0012:  add
                  IL_0013:  stloc.0
                  IL_0014:  ldloc.0
                  IL_0015:  ldarg.0
                  IL_0016:  blt.s      IL_0004
                  IL_0018:  ret
                } // end of method Program::PostIncrement
             */
            for (int i = 0; i < count; i++)
            {
                SomethingToIncrement++;
            }
        }
    }
}

Como o @Jon B diz, não há diferença em um loop for.

Mas em um while ou do...while loop, você pode encontrar algumas diferenças se você está fazendo uma comparação com o ++i ou i++

while(i++ < 10) { ... } //compare then increment

while(++i < 10) { ... } //increment then compare

Em C # não há diferença quando usado em um loop for .

for (int i = 0; i < 10; i++) { Console.WriteLine(i); }

produz a mesma coisa que

for (int i = 0; i < 10; ++i) { Console.WriteLine(i); }

Como outros apontaram, quando usados ​​em geral, i ++ e ++, eu tenho uma diferença sutil, mas significativa:

int i = 0;
Console.WriteLine(i++);   // Prints 0
int j = 0;
Console.WriteLine(++j);   // Prints 1

i ++ lê o valor de i, em seguida, incrementa-o.

++ i incrementa o valor de então lê-lo.


Em javascript devido ao seguinte i ++ pode ser melhor usar:

var i=1;
alert(i++); // before, 1. current, 1. after, 2.
alert(i); // before, 2. current, 2. after, 2.
alert(++i); // before, 2. current, 3 after, 3.

Enquanto arrays (eu acho que todos) e algumas outras funções e chamadas usam 0 como ponto de partida, você teria que definir i como -1 para fazer o loop funcionar com o array ao usar ++ i .

Ao usar o i ++, o valor a seguir usará o valor aumentado. Você poderia dizer que o i ++ é o modo como os humanos contam, porque você pode começar com um 0 .


Há mais para ++ i e i ++ do que loops e diferenças de desempenho. ++ eu retorna um valor-l e i ++ retorna um valor-r. Com base nisso, há muitas coisas que você pode fazer para (++ i), mas não para (i ++).

1- It is illegal to take the address of post increment result. Compiler won't even allow you.
2- Only constant references to post increment can exist, i.e., of the form const T&.
3- You cannot apply another post increment or decrement to the result of i++, i.e., there is no such thing as I++++. This would be parsed as ( i ++ ) ++ which is illegal.
4- When overloading pre-/post-increment and decrement operators, programmers are encouraged to define post- increment/decrement operators like:

T& operator ++ ( )
{
   // logical increment
   return *this;
}

const T operator ++ ( int )
{
    T temp( *this );
    ++*this;
    return temp;
}

Isso me surpreende porque as pessoas podem escrever a expressão de incremento no for-loop como i ++.

Em um loop for, quando o terceiro componente é uma declaração de incremento simples, como em

for (i=0; i<x; i++)  

ou

for (i=0; i<x; ++i)   

não há diferença nas execuções resultantes.


Não há diferença se você não estiver usando o valor após o incremento no loop.

for (int i = 0; i < 4; ++i){
cout<<i;       
}
for (int i = 0; i < 4; i++){
cout<<i;       
}

Ambos os loops imprimirão 0123.

Mas a diferença vem quando você usa o valor após o incremento / decremento no seu loop como abaixo:

Pre Increment Loop:

for (int i = 0,k=0; i < 4; k=++i){
cout<<i<<" ";       
cout<<k<<" "; 
}

Resultado: 0 0 1 1 2 2 3 3

Pós-incremento Loop:

for (int i = 0, k=0; i < 4; k=i++){
cout<<i<<" ";       
cout<<k<<" "; 
}

Resultado: 0 0 1 0 2 1 3 2

Espero que a diferença esteja clara comparando a saída. Aponte para observar aqui que o incremento / decremento é sempre executado no final do loop for e, portanto, os resultados podem ser explicados.


Para i de tipos definidos pelo usuário, esses operadores poderiam (mas não deveriam ) ter semânticas significativamente diferentes no contexto de um índice de loop, e isso poderia (mas não deveria) afetar o comportamento do loop descrito.

Além disso, em c++ , geralmente é mais seguro usar o formulário de pré-incremento ( ++i ) porque é mais facilmente otimizado. (Scott Langham me bateu nesse bocado . Maldito Scott)


Sim existe. A diferença está no valor de retorno. O valor de retorno de "++ i" será o valor após incrementar i. O retorno de "i ++" será o valor antes de incrementar. Isso significa que o código é semelhante ao seguinte:

int a = 0;
int b = ++a; // a is incremented and the result after incrementing is saved to b.
int c = a++; // a is incremented again and the result before incremening is saved to c.

Portanto, a seria 2, ebea cada um deles seria 1.

Eu poderia reescrever o código assim:

int a = 0; 

// ++a;
a = a + 1; // incrementing first.
b = a; // setting second. 

// a++;
c = a; // setting first. 
a = a + 1; // incrementing second. 

Sim, existe uma diferença entre ++i e i++ em um loop for , embora em casos de uso incomuns; quando uma variável de loop com operador de incremento / decremento é usada no bloco for ou dentro da expressão de teste de loop , ou com uma das variáveis ​​de loop . Não, não é simplesmente uma coisa de sintaxe.

Como i em um código significa avaliar a expressão i e o operador não significa uma avaliação, mas apenas uma operação;

  • ++i significa valor de incremento de i por 1 e, posteriormente, i ,
  • i++ significa avaliar i e posterior valor de incremento de i por 1.

Então, o que é obtido de cada duas expressões difere porque o que é avaliado difere em cada uma delas. Tudo o mesmo para --i e --i

Por exemplo;

let i = 0

i++ // evaluates to value of i, means evaluates to 0, later increments i by 1, i is now 1
0
i
1
++i // increments i by 1, i is now 2, later evaluates to value of i, means evaluates to 2
2
i
2

Em casos de uso incomuns, no entanto o próximo exemplo parece útil ou não, não importa, mostra uma diferença

for(i=0, j=i; i<10; j=++i){
    console.log(j, i)
}

for(i=0, j=i; i<10; j=i++){
    console.log(j, i)
}

i ++; ++ i; ambos são semelhantes, pois não são usados ​​em uma expressão.

class A {

     public static void main (String []args) {

     int j = 0 ;
     int k = 0 ;
     ++j;
     k++;
    System.out.println(k+" "+j);

}}

prints out :  1 1

Pré-incremento ++ i aumenta o valor de i e avalia o novo valor incrementado.

int i = 3;
int preIncrementResult = ++i;
Assert( preIncrementResult == 4 );
Assert( i == 4 );

O pós-incremento i ++ incrementa o valor de i e avalia o valor original não incrementado.

int i = 3;
int postIncrementResult = i++;
Assert( postIncrementtResult == 3 );
Assert( i == 4 );

Em C ++, o pré-incremento é geralmente preferido onde você pode usar qualquer um.

Isso porque, se você usar pós-incremento, poderá exigir que o compilador tenha que gerar código que crie uma variável temporária extra. Isso ocorre porque os valores anterior e novo da variável que está sendo incrementada precisam ser mantidos em algum lugar porque podem ser necessários em outro lugar na expressão que está sendo avaliada.

Portanto, em C ++, pelo menos, pode haver uma diferença de desempenho que orienta a sua escolha de qual usar.

Isso é principalmente apenas um problema quando a variável que está sendo incrementada é um tipo definido pelo usuário com um operador ++ sobreposto. Para tipos primitivos (int, etc) não há diferença de desempenho. Mas, vale a pena manter o operador pré-incremental como uma diretriz, a menos que o operador pós-incremento seja definitivamente o que é necessário.

Há mais algumas discussões aqui:
https://web.archive.org/web/20170405054235/http://en.allexperts.com/q/C-1040/Increment-operators.htm

Em C ++, se você estiver usando o STL, talvez esteja usando loops com iteradores. Estes principalmente substituíram os operadores ++, então aderir ao pré-incremento é uma boa idéia. Os compiladores ficam mais inteligentes o tempo todo, e os mais novos podem executar otimizações que significam que não há diferença de desempenho - especialmente se o tipo que está sendo incrementado é definido em linha no arquivo de cabeçalho (como as implementações de STL são frequentemente) para que o compilador possa ver como O método é implementado e pode saber quais otimizações são seguras para executar. Mesmo assim, provavelmente ainda vale a pena aderir ao pré-incremento porque os loops são executados muitas vezes e isso significa que uma pequena penalidade de desempenho pode ser amplificada em breve.

Em outras linguagens como C #, onde o operador ++ não pode ser sobrecarregado, não há diferença de desempenho. Usado em um loop para avançar a variável de loop, os operadores de pré e pós-incremento são equivalentes.

Correção: a sobrecarga ++ em C # é permitida. Parece, porém, que em comparação com C ++, em c # você não pode sobrecarregar as versões de pré e pós de forma independente. Então, eu diria que se o resultado de chamar ++ em C # não for atribuído a uma variável ou usado como parte de uma expressão complexa, o compilador reduzirá as versões anterior e posterior do ++ para o código que executa de maneira equivalente.





pre-increment