¿Existe una diferencia de rendimiento entre i++ y ++i en C++?
Tenemos la pregunta: ¿existe una diferencia de rendimiento entre i++
y ++i
en C ?
¿Cuál es la respuesta para C++?
[Resumen ejecutivo: utilícelo ++i
si no tiene un motivo específico para usarlo i++
].
Para C++, la respuesta es un poco más complicada.
Si i
es un tipo simple (no una instancia de una clase C++), entonces la respuesta dada para C ("No, no hay diferencia de rendimiento") es válida, ya que el compilador está generando el código.
Sin embargo, si i
es una instancia de una clase C++, entonces i++
y ++i
están realizando llamadas a una de las operator++
funciones. Aquí hay un par estándar de estas funciones:
Foo& Foo::operator++() // called for ++i
{
this->data += 1;
return *this;
}
Foo Foo::operator++(int ignored_dummy_value) // called for i++
{
Foo tmp(*this); // variable "tmp" cannot be optimized away by the compiler
++(*this);
return tmp;
}
Dado que el compilador no genera código, sino que simplemente llama a una operator++
función, no hay forma de optimizar la tmp
variable y su constructor de copia asociado. Si el constructor de copias es caro, esto puede tener un impacto significativo en el rendimiento.
Sí. Hay.
El operador ++ puede estar definido o no como una función. Para los tipos primitivos (int, double, ...) los operadores están integrados, por lo que el compilador probablemente podrá optimizar su código. Pero en el caso de un objeto que define el operador ++ la cosa es diferente.
La función operador++(int) debe crear una copia. Esto se debe a que se espera que postfix ++ devuelva un valor diferente al que contiene: debe mantener su valor en una variable temporal, incrementar su valor y devolver la temperatura. En el caso del operador++(), prefijo ++, no es necesario crear una copia: el objeto puede incrementarse y luego simplemente regresar.
He aquí una ilustración del punto:
struct C
{
C& operator++(); // prefix
C operator++(int); // postfix
private:
int i_;
};
C& C::operator++()
{
++i_;
return *this; // self, no copy created
}
C C::operator++(int ignored_dummy_value)
{
C t(*this);
++(*this);
return t; // return a copy
}
Cada vez que llamas a operator++(int) debes crear una copia y el compilador no puede hacer nada al respecto. Cuando tenga la opción, utilice operator++(); De esta manera no guardas una copia. Puede ser significativo en el caso de muchos incrementos (¿bucle grande?) y/o objetos grandes.