He leído que debería evitar el operador de incremento de postfix debido a razones de rendimiento (en ciertos casos).
¿Pero esto no afecta la legibilidad del código? En mi opinión:
for(int i = 0; i < 42; i++);
/* i will never equal 42! */
Se ve mejor que:
for(int i = 0; i < 42; ++i);
/* i will never equal 42! */
Pero esto es probablemente solo por costumbre. Es cierto que no he visto muchos usos ++i
.
¿Es el rendimiento tan malo para sacrificar la legibilidad, en este caso? ¿O simplemente soy ciego y ++i
es más legible que i++
?
c++
readability
postfix
Mateen Ulhaq
fuente
fuente
i++
antes de saber que podría afectar el rendimiento++i
, así que cambié. Al principio, este último parecía un poco extraño, pero después de un tiempo me acostumbré y ahora se siente tan natural comoi++
.++i
yi++
hacer cosas diferentes en ciertos contextos, no asuma que son lo mismo.for (type i = 0; i != 42; ++i)
. No solo seoperator++
puede sobrecargar, sino que también se puedeoperator!=
yoperator<
. El incremento de prefijo no es más caro que el postfix, no igual no es más costoso que menor. ¿Cuáles debemos usar?Respuestas:
Los hechos:
i ++ y ++ i son igualmente fáciles de leer. No te gusta uno porque no estás acostumbrado, pero esencialmente no hay nada que puedas malinterpretar, así que ya no es más trabajo leer o escribir.
En al menos algunos casos, el operador de postfix será menos eficiente.
Sin embargo, en el 99.99% de los casos, no importará porque (a) de todos modos actuará en un tipo simple o primitivo y solo es un problema si está copiando un objeto grande (b) no estará en un rendimiento parte crítica del código (c) no sabe si el compilador lo optimizará o no, puede que lo haga.
Por lo tanto, sugiero que usar prefijo a menos que necesite específicamente postfix es un buen hábito para entrar, solo porque (a) es un buen hábito para ser preciso con otras cosas y (b) una vez en una luna azul, tendrá la intención de usar postfix y dígalo al revés: si siempre escribe lo que quiere decir, es menos probable. Siempre hay una compensación entre rendimiento y optimización.
Debes usar tu sentido común y no micro-optimizar hasta que lo necesites, pero tampoco ser flagrantemente ineficiente por el simple hecho de hacerlo. Por lo general, esto significa: en primer lugar, descartar cualquier construcción de código que sea inaceptablemente ineficiente incluso en un código que no sea crítico para el tiempo (normalmente algo que representa un error conceptual fundamental, como pasar objetos de 500 MB por valor sin ningún motivo); y segundo, de cualquier otra forma de escribir el código, elija el más claro.
Sin embargo, creo que la respuesta es simple: creo que escribir un prefijo a menos que necesite específicamente postfix es (a) muy marginalmente más claro y (b) muy marginalmente más probable que sea más eficiente, por lo que siempre debe escribirlo de forma predeterminada, pero No te preocupes si lo olvidas.
Hace seis meses, pensé lo mismo que tú, que i ++ era más natural, pero es puramente a lo que estás acostumbrado.
EDITAR 1: Scott Meyers, en "C ++ más eficaz", en quien generalmente confío en esto, dice que en general debe evitar usar el operador postfix en tipos definidos por el usuario (porque la única implementación sensata de la función de incremento de postfix es hacer un copia del objeto, llame a la función de incremento de prefijo para realizar el incremento y devuelva la copia, pero las operaciones de copia pueden ser costosas).
Por lo tanto, no sabemos si existen reglas generales sobre (a) si eso es cierto hoy, (b) si también se aplica (menos) a los tipos intrínsecos (c) si debería usar "++" en nada más que una clase de iterador ligero. Pero por todas las razones que describí anteriormente, no importa, haga lo que dije antes.
EDIT 2: Esto se refiere a la práctica general. Si crees que sí importa en algún caso específico, entonces debes perfilarlo y verlo. Perfilar es fácil y barato y funciona. Deducir de los primeros principios lo que debe optimizarse es difícil y costoso y no funciona.
fuente
i++
más que++i
es debido al nombre de un determinado lenguaje de programación muy popular hace referencia en esta pregunta / respuesta ...Siempre codifique para el programador primero y la computadora en segundo lugar.
Si hay una diferencia de rendimiento, después de que el compilador haya echado un ojo experto sobre su código, Y puede medirlo Y es importante, entonces puede cambiarlo.
fuente
GCC produce el mismo código de máquina para ambos bucles.
Código C
Código de Asamblea (con mis comentarios)
fuente
Ahora que esto está fuera de nuestro camino, hagamos nuestra elección con sensatez :
++i
: incrementa el prefijo , incrementa el valor actual y produce el resultadoi++
: incremento de postfix , copia el valor, incrementa el valor actual, produce la copiaA menos que se requiera una copia del valor anterior, el uso del incremento de postfix es una forma práctica de hacer las cosas.
La imprecisión proviene de la pereza, siempre use la construcción que expresa su intención de la manera más directa, hay menos posibilidades de que el futuro mantenedor pueda malinterpretar su intención original.
A pesar de que es (realmente) menor aquí, hay momentos en que me ha intrigado mucho leer el código: realmente me preguntaba si la intención y el expreso real coincidieron y, por supuesto, después de unos meses, ellos (o yo) tampoco lo recordaba ...
Por lo tanto, no importa si te parece bien o no. Abrazo BESO . En unos meses habrás evitado tus viejas prácticas.
fuente
En C ++, tu podrías hacer una diferencia sustancial de rendimiento si hay sobrecargas del operador involucradas, especialmente si está escribiendo código con plantilla y no sabe qué iteradores podrían pasarse. La lógica detrás de cualquier iterador X puede ser sustancial y significativa. es decir, lento e inoptimizable por el compilador.
Pero este no es el caso en C, donde sabe que solo será un tipo trivial, y la diferencia de rendimiento es trivial y el compilador puede optimizar fácilmente.
Un consejo: programa en C, o en C ++, y las preguntas se relacionan con uno u otro, no con ambos.
fuente
El rendimiento de cualquiera de las operaciones depende en gran medida de la arquitectura subyacente. Uno tiene que incrementar un valor que se almacena en la memoria, lo que significa que el cuello de botella de von Neumann es el factor limitante en ambos casos.
En el caso de ++ i, tenemos que
En el caso de i ++, tenemos que
Los operadores ++ y - rastrean su origen al conjunto de instrucciones PDP-11. El PDP-11 podría realizar un post-incremento automático en un registro. También podría realizar un decremento previo automático en una dirección efectiva contenida en un registro. En cualquier caso, el compilador solo podría aprovechar estas operaciones a nivel de máquina si la variable en cuestión fuera una variable de "registro".
fuente
Si quieres saber si algo es lento, pruébalo. Tome un BigInteger o equivalente, péguelo en un bucle similar usando ambos modismos, asegúrese de que el interior del bucle no se optimice y cronometre ambos.
Después de leer el artículo, no me parece muy convincente, por tres razones. Uno, el compilador debería poder optimizar alrededor de la creación de un objeto que nunca se usa. Dos, el
i++
concepto es idiomático para los bucles numéricos , por lo que los casos que puedo ver realmente afectados se limitan a. Tres, proporcionan un argumento puramente teórico, sin números que lo respalden.Sobre la base de la razón n. ° 1 especialmente, supongo que cuando realices el tiempo, estarán uno al lado del otro.
fuente
En primer lugar, no afecta la legibilidad de la OMI. No es lo que estás acostumbrado a ver, pero solo pasará un tiempo antes de que te acostumbres.
En segundo lugar, a menos que use una tonelada de operadores de postfix en su código, es probable que no vea mucha diferencia. El argumento principal para no usarlos cuando sea posible es que se debe mantener una copia del valor de la var original hasta el final de los argumentos donde la var original todavía podría usarse. Eso es 32 bits o 64 bits dependiendo de la arquitectura. Eso equivale a 4 u 8 bytes o 0.00390625 o 0.0078125 MB. Hay muchas posibilidades de que, a menos que esté utilizando una tonelada de ellas que deba guardarse durante un período de tiempo muy largo, con los recursos y la velocidad de la computadora de hoy en día, ni siquiera notará la diferencia al cambiar de postfix a prefijo.
EDITAR: Olvide esta porción restante, ya que mi conclusión resultó ser falsa (excepto por la parte de ++ i e i ++ que no siempre hacen lo mismo ... eso sigue siendo cierto).
También se señaló anteriormente que no hacen lo mismo en algunos casos. Tenga cuidado al hacer el cambio si así lo decide. Nunca lo he probado (siempre he usado postfix), así que no lo sé con certeza, pero creo que cambiar de postfix a prefijo dará como resultado diferentes resultados: (nuevamente podría estar equivocado ... depende del compilador / intérprete también)
fuente
Creo que semánticamente
++i
tiene más sentido quei++
eso, así que me quedaría con el primero, excepto que es común no hacerlo (como en Java, donde debes usari++
porque es muy usado).fuente
No se trata solo de rendimiento.
A veces desea evitar implementar la copia, porque no tiene sentido. Y dado que el uso del incremento de prefijo no depende de esto, es más simple apegarse a la forma de prefijo.
Y usar diferentes incrementos para tipos primitivos y tipos complejos ... eso es realmente ilegible.
fuente
A menos que realmente lo necesite, me quedaría con ++ i. En la mayoría de los casos, esto es lo que se pretende. No es muy frecuente que necesite i ++, y siempre tiene que pensarlo dos veces al leer una construcción de este tipo. Con ++ i, es fácil: agregas 1, lo usas y luego sigo siendo el mismo.
Entonces, estoy totalmente de acuerdo con @martin beckett: hazlo más fácil para ti, ya es bastante difícil.
fuente