Estaba leyendo "El lenguaje de programación C ++" de Stroustrup, donde dice que hay dos formas de agregar algo a una variable
x = x + a;
y
x += a;
Él prefiere +=
porque probablemente esté mejor implementado. Creo que quiere decir que también funciona más rápido.
¿Pero realmente es así? Si depende del compilador y otras cosas, ¿cómo lo compruebo?
c++
performance
operators
Chiffa
fuente
fuente
Respuestas:
Cualquier compilador vale su sal generará exactamente la misma secuencia en lenguaje de máquina para ambas construcciones para cualquier tipo incorporado (
int
,float
, etc.), siempre y cuando la declaración realmente es tan simple comox = x + a;
y optimización está activada . (En particular, GCC-O0
, que es el modo predeterminado, realiza anti-optimizaciones , como insertar almacenes completamente innecesarios en la memoria, para garantizar que los depuradores siempre puedan encontrar valores de variables).Sin embargo, si la declaración es más complicada, pueden ser diferentes. Supongamos que
f
es una función que devuelve un puntero, entoncesllamadas
f
solo una vez, mientras quelo llama dos veces. Si
f
tiene efectos secundarios, uno de los dos estará mal (probablemente el último). Incluso sif
no tiene efectos secundarios, es posible que el compilador no pueda eliminar la segunda llamada, por lo que esta última puede ser más lenta.Y dado que estamos hablando de C ++ aquí, la situación es completamente diferente para los tipos de clases que sobrecargan
operator+
yoperator+=
. Six
es de ese tipo, entonces, antes de la optimización, sex += a
traduce enx.operator+=(a);
mientras que se
x = x + a
traduce enauto TEMP(x.operator+(a)); x.operator=(TEMP);
Ahora, si la clase está escrita correctamente y el optimizador del compilador es lo suficientemente bueno, ambos terminarán generando el mismo lenguaje de máquina, pero no es tan seguro como lo es para los tipos integrados. Esto es probablemente en lo que está pensando Stroustrup cuando fomenta su uso
+=
.fuente
expr
avar
isvar+=expr
y escribirlo de otra manera confundirá a los lectores.*f() = *f() + a;
es posible que desee analizar detenidamente lo que realmente está tratando de lograr ...1
es una constante,a
puede ser volátil, un tipo definido por el usuario o lo que sea. Completamente diferente. De hecho, no entiendo cómo se cerró esto.Puede comprobarlo mirando el desmontaje, que será el mismo.
Para los tipos básicos , ambos son igualmente rápidos.
Esta es la salida generada por una compilación de depuración (es decir, sin optimizaciones):
a += x; 010813BC mov eax,dword ptr [a] 010813BF add eax,dword ptr [x] 010813C2 mov dword ptr [a],eax a = a + x; 010813C5 mov eax,dword ptr [a] 010813C8 add eax,dword ptr [x] 010813CB mov dword ptr [a],eax
Para tipos definidos por el usuario , donde puede sobrecargar
operator +
yoperator +=
, depende de sus respectivas implementaciones.fuente
a
es 1 yx
esvolatile
el compilador podría generarinc DWORD PTR [x]
. Esto es lento.operator +
para no hacer nada yoperator +=
calcular el número primo 100000 y luego regresar. Por supuesto, sería una tontería, pero es posible.++x
ytemp = x + 1; x = temp;
, lo más probable es que deba escribirse en ensamblador en lugar de c ++ ...¡Si! Es más rápido de escribir, más rápido de leer y más rápido de entender, para lo último en el caso de que
x
pueda tener efectos secundarios. Entonces, en general, es más rápido para los humanos. El tiempo humano en general cuesta mucho más que el tiempo de la computadora, así que eso debe ser lo que preguntaba. ¿Derecho?fuente
Realmente depende del tipo de xya y de la implementación de +. por
el compilador tiene que crear una T temporal para contener el valor de x + a mientras lo evalúa, que luego puede asignar a x. (No puede usar xo como espacio de trabajo durante esta operación).
Para x + = a, no necesita un temporal.
Para los tipos triviales, no hay diferencia.
fuente
La diferencia entre
x = x + a
yx += a
es la cantidad de trabajo que debe realizar la máquina: algunos compiladores pueden (y generalmente lo hacen) optimizarla, pero generalmente, si ignoramos la optimización por un tiempo, lo que sucede es que en el fragmento de código anterior, el machine tiene que buscar el valorx
dos veces, mientras que en el último, esta búsqueda debe ocurrir solo una vez.Sin embargo, como mencioné, hoy en día la mayoría de los compiladores son lo suficientemente inteligentes como para analizar la instrucción y reducir las instrucciones de máquina resultantes requeridas.
PD: ¡Primera respuesta en Stack Overflow!
fuente
Como ha etiquetado este C ++, no hay forma de saberlo por las dos declaraciones que ha publicado. Necesita saber qué es 'x' (es un poco como la respuesta '42'). Si
x
es un POD, entonces realmente no hará mucha diferencia. Sin embargo, six
es una clase, puede haber sobrecargas para los métodosoperator +
yoperator +=
que podrían tener diferentes comportamientos que conducen a tiempos de ejecución muy diferentes.fuente
Si dice que
+=
le está haciendo la vida mucho más fácil al compilador. Para que el compilador reconozca quex = x+a
es lo mismo quex += a
, el compilador debeanalice el lado izquierdo (
x
) para asegurarse de que no tenga efectos secundarios y siempre se refiera al mismo valor l. Por ejemplo, podría serloz[i]
, y debe asegurarse de que ambosz
yi
no cambien.analice el lado derecho (
x+a
) y asegúrese de que sea una suma, y que el lado izquierdo aparezca una vez y solo una vez en el lado derecho, aunque podría transformarse, como enz[i] = a + *(z+2*0+i)
.Si lo que quiere decir es agregar
a
ax
, el escritor compilador lo aprecia cuando se acaba de decir lo que quiere decir. De esa manera, no estás ejercitando la parte del compilador de la que su escritor espera que haya eliminado todos los errores, y eso en realidad no te hace la vida más fácil, a menos que honestamente no puedas sacar la cabeza del modo Fortran.fuente
Para un ejemplo concreto, imagine un tipo de número complejo simple:
struct complex { double x, y; complex(double _x, double _y) : x(_x), y(_y) { } complex& operator +=(const complex& b) { x += b.x; y += b.y; return *this; } complex operator +(const complex& b) { complex result(x+b.x, y+b.y); return result; } /* trivial assignment operator */ }
Para el caso a = a + b, tiene que hacer una variable temporal extra y luego copiarla.
fuente
Estás haciendo la pregunta incorrecta.
Es poco probable que esto impulse el rendimiento de una aplicación o función. Incluso si lo fuera, la forma de averiguarlo es perfilar el código y saber con certeza cómo te afecta. En lugar de preocuparse a este nivel por cuál es más rápido, es mucho más importante pensar en términos de claridad, corrección y legibilidad.
Esto es especialmente cierto cuando se considera que, incluso si se trata de un factor de rendimiento significativo, los compiladores evolucionan con el tiempo. Alguien puede encontrar una nueva optimización y la respuesta correcta hoy puede volverse incorrecta mañana. Es un caso clásico de optimización prematura.
Esto no quiere decir que el rendimiento no importe en absoluto ... Solo que es el enfoque incorrecto para lograr sus objetivos de rendimiento. El enfoque correcto es utilizar herramientas de creación de perfiles para saber dónde gasta realmente su tiempo su código y, por lo tanto, dónde centrar sus esfuerzos.
fuente
Creo que eso debería depender de la máquina y su arquitectura. Si su arquitectura permite el direccionamiento indirecto de memoria, el escritor del compilador PODRÍA usar este código en su lugar (para la optimización):
mov $[y],$ACC iadd $ACC, $[i] ; i += y. WHICH MIGHT ALSO STORE IT INTO "i"
Considerando que,
i = i + y
podría traducirse a (sin optimización):Dicho esto,
i
también se deben considerar otras complicaciones, como si es una función que devuelve el puntero, etc. La mayoría de los compiladores de nivel de producción, incluido GCC, producen el mismo código para ambas declaraciones (si son enteros).fuente
No, ambas formas se manejan de la misma manera.
fuente