2011-01-30 25 views
5

Me preguntaba si (aparte de las obvias diferencias de sintaxis) habría una diferencia de eficiencia entre tener una clase que contenga instancias múltiples de un objeto (del mismo tipo) o una tamaño array de objetos de ese tipo.C++ arreglos de tamaño fijo frente a múltiples objetos del mismo tipo

En código:

struct A { 
    double x; 
    double y; 
    double z; 
}; 

struct B { 
    double xvec[3]; 
}; 

En realidad iba a usar boost :: matrices que son una mejor alternativa a C++ matrices de tipo C.

Me preocupa principalmente la construcción/destrucción y la lectura/escritura de estos dobles, porque estas clases a menudo se construirán solo para invocar una de sus funciones miembro una vez.

Gracias por su ayuda/sugerencias.

+3

Las matrices permiten la iteración sobre sus valores, lo que no es posible cuando se usan miembros individuales – Christoph

+1

Cuando tenga una pregunta sobre eficiencia/rendimiento, escriba una pequeña aplicación de prueba y compare. Si tiene problemas para interpretar los resultados, haga una pregunta. –

Respuesta

8

Normalmente, la representación de esas dos estructuras sería exactamente la misma. Sin embargo, es posible que tenga un rendimiento deficiente si elige el incorrecto para su caso de uso.

Por ejemplo, si necesita acceder a cada elemento en un bucle, con un arsenal que podría hacer:

for (int i = 0; i < 3; i++) 
    dosomething(xvec[i]); 

Sin embargo, sin una matriz, que le sea necesario duplicar el código:

dosomething(x); 
dosomething(y); 
dosomething(z); 

Esto significa duplicación de código, que puede ser de cualquier manera. Por un lado, hay menos código de bucle; por otro lado, los bucles muy apretados pueden ser bastante rápidos en los procesadores modernos, y la duplicación de código puede volar el I-caché.

La otra opción es un interruptor:

for (int i = 0; i < 3; i++) { 
    int *r; 
    switch(i) { 
     case 0: r = &x; break; 
     case 1: r = &y; break; 
     case 1: r = &z; break; 
    } 
    dosomething(*r); // assume this is some big inlined code 
} 

Esto evita la posiblemente a gran huella de i-cache, pero tiene un enorme impacto en el rendimiento negativo. No hagas esto

Por otro lado, es, en principio, posible gama accede a ser más lento, si su compilador no es muy inteligente:

xvec[0] = xvec[1] + 1; 
dosomething(xvec[1]); 

Desde xvec [0] y xvec [1] son distinto, en principio, el compilador debería ser capaz de mantener el valor de xvec [1] en un registro, por lo que no tiene que volver a cargar el valor en la siguiente línea. Sin embargo, es posible que algunos compiladores no sean lo suficientemente inteligentes como para notar que xvec [0] y xvec [1] no tienen alias. En este caso, usar campos separados podría ser un poco más rápido.

En resumen, no se trata de que una u otra sea rápida en todos los casos. Se trata de hacer coincidir la representación con la forma en que la usas.

Personalmente, le sugiero que vaya con lo que sea que haga que el código que funciona en xvec sea más natural. No vale la pena pasar mucho tiempo humano preocupándose por algo que, en el mejor de los casos, probablemente solo produzca una diferencia de rendimiento tan pequeña que solo la detectará en micro-puntos de referencia.

1

Depende. Por ejemplo, el ejemplo que dio es un clásico en favor de arrays 'vieja escuela': un punto/vector matemáticas (o matriz)

  • tiene un número fijo de elementos
  • los datos en sí es por lo general guardado privada en un objeto
  • ya que (si?) que tiene una clase como una interfaz , puede adecuadamente inicializarlas en el constructor (de lo contrario, clásico gama inialization es algo que no me gusta mucho , sintaxis)

En tales casos (yendo con los ejemplos de matriz/vector matemático), siempre terminé usando matrices de estilo C internamente, ya que puede recorrerlas en lugar de escribir código de copia/pegado para cada componente.

Pero este es un caso especial - para mí, en C++ hoy en día matrices == vector de STL, es rápido y no tener que preocuparse por el nuthin :)

+0

Hay una diferencia entre 'std :: vector ' y 'std :: array ', por lo que no compararía matrices con vectores. – fredoverflow

-1

matrices primas ofrecen una mejor localización de caché matrices de C++, tal como se presenta, la única ventaja del ejemplo de matriz sobre los objetos múltiples es la capacidad de iterar sobre los elementos.

La respuesta real es, por supuesto, crear un caso de prueba y medir.

+3

Los arreglos en C++ se presentan en la memoria exactamente como los arrays en C. Una matriz C++ es simplemente una estructura con un solo miembro de la matriz C. – fredoverflow

+0

Nunca he medido esto, pero un vector STL debe proporcionar la misma localidad de caché que una matriz C si se usa de la misma manera (es decir, especificar el número de elementos en init y no hacer que vuelva a asignar memoria al ir sobre el límite'). – riviera

+0

Ya sabes, eso es técnicamente cierto. Entonces quizás estaba siendo falso. Sin embargo, la consecuencia lógica del uso de clases genéricas en lugar de tipos nativos sin procesar conduce al uso inevitable del puntero inteligente y otros objetos de envoltura. –

5

MVC++ 2010 generó exactamente el mismo código para lectura/escritura de dos estructuras POD como en su ejemplo. Dado que los desplazamientos para leer/escribir son computables en tiempo de compilación, esto no es sorprendente. Lo mismo ocurre con la construcción y la destrucción.

En cuanto al rendimiento real, se aplica la regla general: perfilar si es importante, si no es así - ¿por qué preocuparse?

La indexación en un miembro de la matriz es tal vez un poco más trabajo para el usuario de su estructura, pero una vez más, puede iterar más fácilmente sobre los elementos.

+0

Muy interesante hallazgo, ¡gracias por informar esto! (También estoy usando VS2010: P) – stepelu

2

En caso de que no se puede decidir y quiere mantener sus opciones abiertas, se puede utilizar una unión anónima:

struct Foo 
{ 
    union 
    { 
     struct 
     { 
      double x; 
      double y; 
      double z; 
     } xyz; 
     double arr[3]; 
    }; 
}; 

int main() 
{ 
    Foo a; 
    a.xyz.x = 42; 
    std::cout << a.arr[0] << std::endl; 
} 

Algunos compiladores también soportan estructuras anónimas, en ese caso, puede dejar la parte xyz a cabo .

+0

Aunque no es estándar, el soporte para uniones anónimas es bastante común: tanto GCC como MSVC las admiten. También se han agregado uniones anónimas al próximo estándar de lenguaje C1X, aunque eso está muy lejos de ser estandarizado e implementado (diablos, el soporte C99 es bastante patético, ¡y ese estándar ya tiene 12 años!). –

+0

@ Adam Rosenfield: los sindicatos anónimos son estándar en C++, consulte 9.5.4 – Oystein

+0

Quise decir 9.5.2, lo siento. – Oystein

1

La diferencia puede estar en almacenar las variables en la memoria. En el primer ejemplo, el compilador puede agregar relleno para alinear los datos. Pero en tu caso particular, no importa.

Cuestiones relacionadas