You are currently browsing the tag archive for the ‘prefijo mejor que postfijo’ tag.

Hay una experiencia en la programación que dice

Primero hazlo funcionar, entonces hazlo rápido.

Lo que quiere decir es que no te preocupes (demasiado) sobre la velocidad con que tu programa se ejecutará a la hora de crear.

Esto viene de la experiencia que los problemas de velocidad muchas veces surgen de donde no se pueden predecir. Poco sirve optimizar un código para que corra un 30% más rápido cuando la mayor parte del tiempo no hace nada más que esperar a una conexión de red lenta. Comprar un ordenador más potente es muchas veces más barato que pagar un programador para optimizar el código. (De hecho un ordenador nuevo cuesta menos que un salario mensual.) Tampoco afecta mucho al programa entero cambiar esa sentencia SQL lenta por una más optima. Salvo en entornos concretos como el tratamiento de datos en tiempo real, la velocidad del código no es tan importante como la velocidad del programador para terminar el programa.

No obstante hay unas prácticas de programación que suben la velocidad de ejecución sin perder mucho tiempo a la hora de usarlas. Aquí presentamos algunas de ellas.

Evita llamar a las mismas funciones con los mismos parámetros. Una llamada a la misma función con los mismos parámetros suele devolver el mismo resultado. Es más rápido guardar este resultado en una variable (o constante) y usar su valor, porque en general no podemos saber si la función ejecuta un cálculo costoso en cada llamada. En el caso más rápido la función no hace otra cosa que devolver un simple valor, pero nunca va a ser más rápida que la variable. Esta regla es especialmente importante cuando su valor de retorno es usado en una condición de fin de bucle.

Es decir, en lugar de una construcción así

for (int i = 0; i < tamaño_de_mi_vector(); ++i)
{
    // Haz algo
}

usar esta práctica

const int tamaño = tamaño_de_mi_vector();
for (int i = 0; i < tamaño; ++i)
{
    // Haz algo
}

Evitar funciones con muchos parámetros. Cada parámetro incluye una copia de algo. Separa el código de una forma que minimiza el número de parámetros. Es cierto que lo óptimo por este punto de vista sería no separar el código en absoluto, pero tampoco queremos perder de la vista la velocidad del programador de entender el programa.

No devolver arrays y objetos grandes. Lo que es un objeto grande depende del lenguaje. C++ devuelve una copia de un objeto (costoso), Java y PHP devuelven nada más una referencia (rápida). Sin embargo, PHP copia los arrays. Es decir devolver un objeto que contiene un array es más rápido en PHP que devolver directamente el array. C++ permite devolver referencias a objetos también, pero el programador debe asegurar que el objeto existe después de la llamada a la función. Una manera de conseguirlo es que el valor de «retorno» es una referencia a un objeto que suministra el usuario de la función como parámetro.

// Esta devolución llama a un constructor de copia.
UnaClase una_funcion()
{
    UnaClase un_objeto;
    return un_objeto;
}

// Esta función pide como parámetro el objeto donde escribir el resultado.
// Nota el ampersand & que indica la referencia en lugar de copia.
// La función no necesita devolver ningún valor.
void otra_funcion(UnaClase& referencia_a_resultado)
{
    referencia_a_resultado = // lo que tú quieras
}

// Estas funciones se llamarían así.
// Nota que la técnica de pasar una referencia no permite declarar
// la variable constante.
const UnaClase un_valor = una_funcion();
UnaClase otro_valor;
otra_funcion(otro_valor);

Usar el incremento/decremento pre-fix en lugar de post-fix para operadores sobrecargados (en C++). Esto suele «ahorrar» dos llamadas al constructor de copia. Este tema está tratado en un artículo específico.

El lenguaje C++, como muchos otros lenguajes, tiene un operador de incremento pre-fix y post-fix. El operador pre-fix ++p tiene el mismo efecto sobre una variable entera int p como un incremento post-fix p++: el valor se incrementa en uno. La diferencia está que la expresión ++p evalúa al valor de p después del incremento (pre-fix como pre como primero), mientras la expresión p++ tiene el valor de p antes del incremento (post como después). Sin embargo, en muchas ocasiones no se hace uso de esta diferencia y simplemente se quiere añadir uno a la variable p.

No importa mucho qué operador se usa para tipos básicos, porque el compilador añade el cálculo de «más uno» en el código ejecutable donde hace falta. Sin embargo hay una diferencia importante cuando se usan operadores sobrecargados en clases. Lo mismo que vamos a demostrar aquí para un operador de incremento ++ vale también para un operador de decremento --.

Una típica implementación de un incremento sobrecargado sería algo así:

class MiClase
{
private:
    int mi_valor;
public:
    // El operador pre-fix (argumento void)
    MiClase& operator++(void)
    {
        // Increméntame internamente (también puedo usar ++mi_valor)
        mi_valor += 1;

        // Devuelve una referencia a mí mismo
        return *this;
    }

    // El operador post-fix (argumento int sin nombre)
    MiClase operator++(int)
    {
        // Guarda una copia en una instancia temporal
        MiClase temp(*this);

        // Increméntame internamente (también puedo usar ++mi_valor)
        mi_valor += 1;

        // Devuelve la copia temporal con el estado anterior
        return temp;
    }
};

A primera vista vemos que el pre-incremento es mucho más simple. Incrementa el estado de la clase y devuelve una referencia a la instancia.

El post-incremento es más complicado. Tengo que crear una copia para no perder el estado anterior que finalmente devuelvo también como copia y no como referencia. Es decir, tengo que llamar dos veces al constructor de copia cuando no necesito hacerlo para el operador pre-fix.

Por este motivo es preferible usar el operador pre-fix para incrementar y decrementar objetos. Aunque esta regla no sea necesario para variables de tipos básicos es preferible hacerlo para tener un estilo único.

Escribe tu dirección de correo electrónico para suscribirte a este blog, y recibir notificaciones de nuevos mensajes por correo.

Únete a otros 61 suscriptores

Archivos

May 2024
L M X J V S D
 12345
6789101112
13141516171819
20212223242526
2728293031