2012-06-13 12 views
5

Tengo dos preguntas relacionadas, una general y una específica para el proyecto en el que estoy trabajando.bucles, diseño de funciones y eficiencia: dos preguntas

  1. Generalmente si tengo un bucle con una gran cantidad de iteraciones (millones) con algunas partes del código que se está ejecutando bajo ciertas condiciones, es mejor (más eficiente) a tener un bucle con múltiples sentencias condicionales o varios bucles sin ellos. P.ej.

ejemplo 1:

while (something()) 
{ 
    // some common code 
    if (condition_a) 
     // some code 
    if (condition_b) 
     // some code 
    // some more common code 
} 

ejemplo 2:

if (condition_a && condition_b) 
{ 
    while (something()) 
    { 
     // some common and specific code 
    } 
} 
else if (condition_a) 
    while (something()) //.. 
else if (condition_b) 
    // Another loop 
else //... 

Parece que el ejemplo 2 se traduciría en un código más eficiente en el costo de la redundancia ya que las condiciones se comprueban una sola vez en lugar de millones de veces Sin embargo, si el código común es enorme o hay muchas condiciones posibles, esto parece extremadamente redundante.

  1. Ahora a mi problema específico. Tengo una función que lee puntos de un archivo y los inserta en una estructura de datos. Se ve algo como esto:

    tiempo (lector-> read_point) {// hacer algunas cosas // punto de inserción }

El problema es que hay varias funciones para la lectura de una punto que debe usarse según los criterios proporcionados por el usuario. Por ejemplo read_point_inside_circle(), read_point_inside_rectangle() etc.

Idealmente, me gustaría utilizar un puntero a función para decidir sobre la función correcta de antemano, sin embargo no creo que sea posible ya que el lector es una instancia de una clase Reader (si es posible de alguna manera eso resolvería todos mis problemas).

En esta situación, es mejor si tengo varios bucles que difieren solo por la condición o si debo usar múltiples instrucciones if para evitar el código redundante, por ejemplo.

for(;;) 
{ 
    if (read_every_point) 
     if(!reader->read_point()) 
      break; 
    else if (read_inside_circle) 
     if(!reader->read_inside_circle()) 
      break; 
    else if // ... 
} 
+2

Dudo que el primero tenga algún efecto en cualquier compilador moderno. Me gustaría ir con lo que es más legible y dejar que el compilador optimice eso para mí. – amit

Respuesta

2

Idealmente me gustaría utilizar un puntero de función para decidir sobre la función correcta de antemano, sin embargo, no creo que sea posible desde el lector es una instancia de una clase de lector (si es posible de alguna manera eso resolvería todos mis problemas).

Puede utilizar punteros de función miembro de para eso, suponiendo que todo el leer funciones tienen la misma firma:

typedef void (Reader::*read_fun_t)(); 
read_fun_t read_fun = &Reader::read_point; 
// or 
read_fun_t read_fun = &Reader::read_inside_circle; 

... 

(reader->*read_fun)(); 

o si no se siente cómodo con ellos, simplemente crear su propias funciones gratuitas que envuelven las llamadas a los métodos:

void read_point(Reader* reader){ reader->read_point(); } 
void read_inside_circle(Reader* reader){ reader->read_inside_circle(); } 

y usan punteros de funciones regulares en su lugar.

+0

Esto realmente funcionó, pero lamentablemente mis funciones toman diferentes parámetros: read_point(), inside_circle (F64 center_x, F64 center_y, F64 radius), inner_rectangle (F64 min_x, F64 max_x, ...). ¿Hay alguna forma de evitar esto? – jaho

+0

@Marian: si los parámetros son _loop invariant_, entonces los objetos de función de nivel superior y los enlazadores funcionarán. Busque 'std | boost :: function' y' std | boost :: bind'. –

3

Para responder a su pregunta específica: el tiempo que toma leer un archivo va a abrumar el tiempo pasado en el if/else. Escribe lo que sea más legible. Por lo general, es más eficiente y no lo optimiza hasta que haya demostrado que es un cuello de botella.

Para responder a su pregunta general: depende de muchas cosas y los compiladores modernos son muy buenos para hacer las cosas con eficiencia independientemente de su intuición. Entonces, es una discusión teórica hasta que tenga código de trabajo en un compilador y arquitectura específicos.

Cuestiones relacionadas