Incrementando en C ++ – ¿Cuándo usar x ++ o ++ x?

Actualmente estoy aprendiendo C ++ y aprendí sobre el incremento hace un tiempo. Sé que puedes usar “++ x” para hacer el incremento antes y “x ++” para hacerlo después.

Aún así, realmente no sé cuándo usar cualquiera de los dos … Nunca he usado “++ x” y las cosas siempre funcionaron bien hasta ahora, entonces, ¿cuándo debería usarlo?

Ejemplo: en un bucle for, ¿cuándo es preferible usar “++ x”?

Además, ¿podría alguien explicar exactamente cómo funcionan las diferentes incrementos (o decrementaciones)? Yo realmente lo apreciaría.

No es una cuestión de preferencia, sino de lógica.

x++ incrementa el valor de la variable x después de procesar la statement actual.

++x incrementa el valor de la variable x antes de procesar la statement actual.

Así que solo decide sobre la lógica que escribes.

x += ++i boosté i y añadiré i + 1 a x. x += i++ agregará i a x, luego incrementará i.

Scott Meyers le dice que prefiera el prefijo, excepto en aquellas ocasiones en que la lógica dictaría que el postfix es apropiado.

“Artículo 6 más eficaz” , es suficiente autoridad para mí.

Para aquellos que no poseen el libro, aquí están las citas pertinentes. De la página 32:

A partir de sus días como progtwigdor en C, puede recordar que la forma de prefijo del operador de incremento a veces se denomina “incremento y recuperación”, mientras que el formulario de postfijo a menudo se conoce como “recuperación e incremento”. Las dos frases son importantes para recordar, porque todas actúan como especificaciones formales …

Y en la página 34:

Si usted es del tipo que se preocupa por la eficiencia, es probable que se ponga a sudar cuando vea por primera vez la función de incremento de postfijación. Esa función tiene que crear un objeto temporal para su valor de retorno y la implementación anterior también crea un objeto temporal explícito que debe ser construido y destruido. La función de incremento de prefijo no tiene tales temporarios …

Desde cppreference al incrementar iteradores:

Debería preferir el operador de preincremento (++ iter) al operador de postincremento (iter ++) si no va a utilizar el valor anterior. El incremento posterior generalmente se implementa de la siguiente manera:

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

Obviamente, es menos eficiente que el pre-incremento.

El preincremento no genera el objeto temporal. Esto puede hacer una gran diferencia si su objeto es costoso de crear.

Solo quiero observar que el código generado se utiliza de la misma manera si se usa el incremento pre / post donde la semántica (de pre / post) no importa.

ejemplo:

pre.cpp:

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

post.cpp:

 #include  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" 

Lo más importante a tener en cuenta, imo, es que x ++ necesita devolver el valor antes de que el incremento realmente tenga lugar, por lo tanto, tiene que hacer una copia temporal del objeto (incremento previo). Esto es menos eficiente que ++ x, que se incrementa en el lugar y se devuelve.

Sin embargo, otra cosa que vale la pena mencionar es que la mayoría de los comstackdores podrán optimizar tales cosas innecesarias cuando sea posible, por ejemplo, ambas opciones llevarán al mismo código aquí:

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

Estoy de acuerdo con @BeowulfOF, aunque para mayor claridad, siempre recomendaría dividir las declaraciones para que la lógica sea absolutamente clara, es decir:

 i++; x += i; 

o

 x += i; i++; 

Entonces mi respuesta es que si escribes un código claro, esto rara vez importará (y si es importante, entonces tu código probablemente no sea lo suficientemente claro).

Solo quería volver a enfatizar que se espera que ++ x sea más rápido que x ++, (especialmente si x es un objeto de algún tipo arbitrario), por lo tanto, a menos que sea necesario por razones lógicas, se debe usar ++ x.

Usted explicó la diferencia correctamente. Solo depende de si desea que x incremente antes de cada ejecución a través de un bucle, o después de eso. Depende de la lógica de tu progtwig, lo que es apropiado.

Una diferencia importante cuando se trata con STL-Iterators (que también implementan estos operadores) es que ++ crea una copia del objeto al que apunta el iterador, luego se incrementa y luego devuelve la copia. ++, por otro lado, hace el incremento primero y luego devuelve una referencia al objeto al que ahora apunta el iterador. Esto es principalmente relevante cuando todo el rendimiento cuenta o cuando implementa su propio STL-iterator.

Editar: corrigió la mezcla de notación de prefijo y sufijo

Comprender la syntax del lenguaje es importante cuando se considera la claridad del código. Considere copiar una cadena de caracteres, por ejemplo, con un incremento posterior:

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

Queremos que el ciclo se ejecute al encontrar el carácter cero (que prueba falso) al final de la cadena. Eso requiere probar el valor previo al incremento y también incrementar el índice. Pero no necesariamente en ese orden, una forma de codificar esto con el pre-incremento sería:

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

Es una cuestión de gustos que es más clara y si la máquina tiene un puñado de registros, ambos deberían tener un tiempo de ejecución idéntico, incluso si a [i] es una función que es cara o tiene efectos secundarios. Una diferencia significativa podría ser el valor de salida del índice.

La forma Postfix de ++, – el operador sigue la regla use-then-change ,

El formulario de prefijo (++ x, – x) sigue la regla change-then-use .

Ejemplo 1:

Cuando se conectan en cascada múltiples valores con << usando cout entonces los cálculos (si los hay) tienen lugar de derecha a izquierda, pero la impresión se lleva a cabo de izquierda a derecha, por ejemplo, (si val si inicialmente 10)

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

dará lugar a

 12 10 10 

Ejemplo 2:

En Turbo C ++, si se encuentran múltiples ocurrencias de ++ o (en cualquier forma) en una expresión, primero se calculan todas las formas de prefijo, luego se evalúa la expresión y finalmente se calculan los formularios de postfix, por ejemplo,

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

Su salida en Turbo C ++ será

 48 13 

Mientras que su salida en comstackdor moderno será (porque siguen estrictamente las reglas)

 45 13 
  • Nota: no se recomienda el uso múltiple de operadores de incremento / decremento en la misma variable en una expresión. El manejo / resultados de tal
    las expresiones varían de comstackdor a comstackdor.