Siempre he pensado que es la sabiduría general que std::vector
se "implementa como una matriz", bla, bla, bla. Hoy bajé y lo probé, y parece que no es así:
Aquí hay algunos resultados de la prueba:
UseArray completed in 2.619 seconds
UseVector completed in 9.284 seconds
UseVectorPushBack completed in 14.669 seconds
The whole thing completed in 26.591 seconds
¡Eso es entre 3 y 4 veces más lento! Realmente no justifica los vector
comentarios de " puede ser más lento para unos pocos nanosecs".
Y el código que usé:
#include <cstdlib>
#include <vector>
#include <iostream>
#include <string>
#include <boost/date_time/posix_time/ptime.hpp>
#include <boost/date_time/microsec_time_clock.hpp>
class TestTimer
{
public:
TestTimer(const std::string & name) : name(name),
start(boost::date_time::microsec_clock<boost::posix_time::ptime>::local_time())
{
}
~TestTimer()
{
using namespace std;
using namespace boost;
posix_time::ptime now(date_time::microsec_clock<posix_time::ptime>::local_time());
posix_time::time_duration d = now - start;
cout << name << " completed in " << d.total_milliseconds() / 1000.0 <<
" seconds" << endl;
}
private:
std::string name;
boost::posix_time::ptime start;
};
struct Pixel
{
Pixel()
{
}
Pixel(unsigned char r, unsigned char g, unsigned char b) : r(r), g(g), b(b)
{
}
unsigned char r, g, b;
};
void UseVector()
{
TestTimer t("UseVector");
for(int i = 0; i < 1000; ++i)
{
int dimension = 999;
std::vector<Pixel> pixels;
pixels.resize(dimension * dimension);
for(int i = 0; i < dimension * dimension; ++i)
{
pixels[i].r = 255;
pixels[i].g = 0;
pixels[i].b = 0;
}
}
}
void UseVectorPushBack()
{
TestTimer t("UseVectorPushBack");
for(int i = 0; i < 1000; ++i)
{
int dimension = 999;
std::vector<Pixel> pixels;
pixels.reserve(dimension * dimension);
for(int i = 0; i < dimension * dimension; ++i)
pixels.push_back(Pixel(255, 0, 0));
}
}
void UseArray()
{
TestTimer t("UseArray");
for(int i = 0; i < 1000; ++i)
{
int dimension = 999;
Pixel * pixels = (Pixel *)malloc(sizeof(Pixel) * dimension * dimension);
for(int i = 0 ; i < dimension * dimension; ++i)
{
pixels[i].r = 255;
pixels[i].g = 0;
pixels[i].b = 0;
}
free(pixels);
}
}
int main()
{
TestTimer t1("The whole thing");
UseArray();
UseVector();
UseVectorPushBack();
return 0;
}
¿Lo estoy haciendo mal o algo así? ¿O acabo de romper este mito del rendimiento?
Estoy usando el modo Release en Visual Studio 2005 .
En Visual C ++ , se #define _SECURE_SCL 0
reduce UseVector
a la mitad (reduciéndolo a 4 segundos). Esto es realmente enorme, en mi opinión.
vector
es una matriz redimensionable de uso general. Felicidades. Al igual que con todas las herramientas de uso general, es posible encontrar situaciones especializadas en las que es subóptimo. Es por eso que la sabiduría convencional es comenzar convector
y considerar alternativas si es necesario.Respuestas:
Usando lo siguiente:
Entonces array es dos veces más rápido que vector.
Pero después de mirar el código con más detalle, esto se espera; mientras corres por el vector dos veces y la matriz solo una vez. Nota: cuando utiliza
resize()
el vector, no solo asigna la memoria, sino que también lo ejecuta y llama al constructor de cada miembro.Reorganizar el código ligeramente para que el vector solo inicialice cada objeto una vez:
Ahora haciendo el mismo tiempo nuevamente:
El vector ahora solo tiene un rendimiento ligeramente peor que la matriz. En mi opinión, esta diferencia es insignificante y podría ser causada por un montón de cosas no asociadas con la prueba.
También tendría en cuenta que no está inicializando / Destruyendo correctamente el objeto Pixel en el
UseArrray()
método ya que no se llama a ningún constructor / destructor (esto puede no ser un problema para esta clase simple sino algo un poco más complejo (es decir, con punteros o miembros) con punteros) causará problemas.fuente
reserve()
lugar deresize()
. Esto asigna espacio para los objetos (es decir, cambia la capacidad del vector) pero no crea los objetos (es decir, el tamaño del vector no se modifica).resize()
conreserve()
, porque esto no se ajusta idea interna del vector de su propio tamaño, por lo que las escrituras posteriores a sus elementos son técnicamente "escribir más allá del final" y producirá UB. Aunque en la práctica cada implementación de STL se "comportará" en ese sentido, ¿cómo se sincroniza el tamaño del vector? Si intenta llamarresize()
después de llenar el vector, ¡posiblemente sobrescribirá todos esos elementos con valores construidos por defecto!reserve
solo cambia la capacidad de un vector, no su tamaño./EHsc
a los conmutadores de compilación limpió eso, y enassign()
realidad supera a la matriz ahora. Hurra.Gran pregunta Entré aquí esperando encontrar alguna solución simple que aceleraría las pruebas de vectores. ¡Eso no funcionó como esperaba!
La optimización ayuda, pero no es suficiente. Con la optimización activada, sigo viendo una diferencia de rendimiento 2X entre UseArray y UseVector. Curiosamente, UseVector fue significativamente más lento que UseVectorPushBack sin optimización.
Idea # 1 - Use new [] en lugar de malloc
Intenté cambiar
malloc()
anew[]
UseArray para que los objetos se construyeran. Y cambiando de la asignación de campo individual a la asignación de una instancia de Pixel. Ah, y renombrar la variable del bucle interno aj
.Sorprendentemente (para mí), ninguno de esos cambios hizo alguna diferencia. Ni siquiera el cambio al
new[]
cual se construirá por defecto todos los píxeles. Parece que gcc puede optimizar las llamadas de constructor predeterminadas cuando se usanew[]
, pero no cuando se usavector
.Idea # 2 - Eliminar llamadas repetidas del operador []
También intenté deshacerme del triple
operator[]
búsqueda y almacenar en caché la referenciapixels[j]
. ¡Eso en realidad ralentizó UseVector! UpsIdea # 3 - Eliminar constructores
¿Qué pasa con la eliminación de los constructores por completo? Entonces, quizás gcc puede optimizar la construcción de todos los objetos cuando se crean los vectores. ¿Qué sucede si cambiamos Pixel a:
Resultado: aproximadamente un 10% más rápido. Todavía más lento que una matriz. Hm.
Idea # 4: usar iterador en lugar de índice de bucle
¿Qué tal usar un
vector<Pixel>::iterator
índice de bucle en lugar de un?Resultado:
No, no es diferente. Al menos no es más lento. Pensé que esto tendría un rendimiento similar al # 2 donde usé un
Pixel&
referencia.Conclusión
Incluso si alguna cookie inteligente descubre cómo hacer que el bucle vectorial sea tan rápido como el array, esto no habla bien del comportamiento predeterminado de
std::vector
. Demasiado para que el compilador sea lo suficientemente inteligente como para optimizar todo C ++ ness y hacer que los contenedores STL sean tan rápidos como los arreglos sin formato.La conclusión es que el compilador no puede optimizar las llamadas de constructor predeterminadas no operativas cuando se usa
std::vector
. Si usas simplenew[]
, los optimiza muy bien. Pero no constd::vector
. Incluso si puede reescribir su código para eliminar las llamadas de constructor que se oponen al mantra por aquí: "El compilador es más inteligente que usted. El STL es tan rápido como el simple C. No se preocupe".fuente
vector<int>
.Esta es una pregunta antigua pero popular.
En este punto, muchos programadores trabajarán en C ++ 11. Y en C ++ 11, el código del OP como está escrito se ejecuta igualmente rápido para
UseArray
oUseVector
.El problema fundamental era que, si bien su
Pixel
estructura no estaba inicializada,std::vector<T>::resize( size_t, T const&=T() )
toma una construcción predeterminadaPixel
y la copia . El compilador no se dio cuenta de que se le pedía que copiara datos no inicializados, por lo que realmente realizó la copia.En C ++ 11,
std::vector<T>::resize
tiene dos sobrecargas. El primero esstd::vector<T>::resize(size_t)
, el otro esstd::vector<T>::resize(size_t, T const&)
. Esto significa que cuando invocaresize
sin un segundo argumento, simplemente construye por defecto, y el compilador es lo suficientemente inteligente como para darse cuenta de que la construcción por defecto no hace nada, por lo que omite el paso sobre el búfer.(Las dos sobrecargas se agregaron para manejar tipos móviles, construibles y no copiables: la mejora del rendimiento cuando se trabaja con datos no inicializados es una ventaja).
La
push_back
solución también verifica el poste de la cerca, lo que lo ralentiza, por lo que sigue siendo más lento que lamalloc
versión.ejemplo en vivo (también reemplacé el temporizador con
chrono::high_resolution_clock
).Tenga en cuenta que si tiene una estructura que generalmente requiere inicialización, pero desea manejarla después de aumentar su búfer, puede hacerlo con un
std::vector
asignador personalizado . Si desea moverlo a una situación más normalstd::vector
, creo que el uso cuidadosoallocator_traits
y la anulación de esto==
podrían lograrlo, pero no estoy seguro.fuente
emplace_back
funciona vspush_back
aquí.clang++ -std=c++11 -O3
tieneUseArray completed in 2.02e-07 seconds
yUseVector completed in 1.3026 seconds
. También agregué unaUseVectorEmplaceBack
versión que es de aprox. 2.5x más rápido queUseVectorPushBack
.Para ser justos, no puede comparar una implementación de C ++ con una implementación de C, como yo llamaría su versión de malloc. malloc no crea objetos, solo asigna memoria en bruto. Que luego trates esa memoria como objetos sin llamar al constructor es pobre en C ++ (posiblemente inválido, lo dejaré a los abogados de lenguaje).
Dicho esto, simplemente cambiar malloc a
new Pixel[dimensions*dimensions]
free todelete [] pixels
no hace mucha diferencia con la simple implementación de Pixel que tienes. Aquí están los resultados en mi caja (E6600, 64 bits):Pero con un ligero cambio, las cosas cambian:
Pixel.h
Pixel.cc
main.cc
Compilado de esta manera:
obtenemos resultados muy diferentes:
Con un constructor no en línea para Pixel, std :: vector ahora supera a una matriz en bruto.
Parece que la complejidad de la asignación a través de std :: vector y std: allocator es demasiado para ser optimizada de manera tan efectiva como simple
new Pixel[n]
. Sin embargo, podemos ver que el problema es simplemente con la asignación, no el acceso al vector, ajustando un par de funciones de prueba para crear el vector / matriz una vez, moviéndolo fuera del ciclo:y
Obtenemos estos resultados ahora:
Lo que podemos aprender de esto es que std :: vector es comparable a una matriz en bruto para el acceso, pero si necesita crear y eliminar el vector / matriz muchas veces, crear un objeto complejo requerirá más tiempo que crear una matriz simple cuando el constructor del elemento no está en línea. No creo que esto sea muy sorprendente.
fuente
Prueba con esto:
Obtengo casi exactamente el mismo rendimiento que con la matriz.
La cuestión
vector
es que es una herramienta mucho más general que una matriz. Y eso significa que tienes que considerar cómo lo usas. Se puede usar de muchas maneras diferentes, proporcionando una funcionalidad que una matriz ni siquiera tiene. Y si lo usa "mal" para su propósito, incurrirá en una sobrecarga, pero si lo usa correctamente, generalmente es básicamente una estructura de datos de sobrecarga cero. En este caso, el problema es que usted inicializó el vector por separado (haciendo que todos los elementos tengan su ctor predeterminado llamado) y luego sobrescribiendo cada elemento individualmente con el valor correcto. Eso es mucho más difícil de optimizar para el compilador que cuando haces lo mismo con una matriz. Es por eso que el vector proporciona un constructor que le permite hacer exactamente eso: .N
X
Y cuando usas eso, el vector es tan rápido como una matriz.
Entonces no, no has roto el mito del rendimiento. Pero ha demostrado que solo es cierto si usa el vector de manera óptima, lo cual es un punto bastante bueno también. :)
En el lado positivo, es realmente el uso más simple que resulta ser el más rápido. Si contrasta mi fragmento de código (una sola línea) con la respuesta de John Kugelman, que contiene montones y montones de ajustes y optimizaciones, que aún no eliminan la diferencia de rendimiento, está bastante claro que
vector
, después de todo, está muy bien diseñado. No tiene que saltar a través de aros para obtener una velocidad igual a una matriz. Por el contrario, debe usar la solución más simple posible.fuente
new[]
realiza las mismas construcciones predeterminadas quevector.resize()
hace, pero es mucho más rápido.new[]
El bucle interno debe tener la misma velocidad quevector.resize()
el bucle interno, pero no lo es, es casi el doble de rápido.malloc
que no se inicializa ni construye nada, por lo que es efectivamente un algoritmo de un solo paso al igual que mivector
muestra. Y en cuanto anew[]
la respuesta, obviamente, ambos requieren dos pases, pero en elnew[]
caso, el compilador puede optimizar esa sobrecarga adicional, lo que no hace en elvector
caso. Pero no veo por qué es interesante lo que sucede en casos subóptimos. Si te importa el rendimiento, no escribes código como ese.vector::resize()
que me brinde una gran cantidad de memoria sin perder el tiempo llamando a constructores inútiles.malloc
que no realiza la inicialización, pero eso no funcionará en C ++ con tipos que no sean POD. Entonces, en el caso general, una matriz C ++ sería igual de mala. Quizás la pregunta es, si va a realizar este blit a menudo, ¿no reutilizaría la misma matriz / vector? Y si hace eso, solo paga el costo de "constructores inútiles" una vez, desde el principio. El bliting real es igual de rápido después de todo.No fue una comparación justa cuando vi por primera vez su código; Definitivamente pensé que no estabas comparando manzanas con manzanas. Entonces pensé, vamos a llamar a los constructores y destructores en todas las pruebas; y luego comparar.
Pensé que, con esta configuración, deberían ser exactamente lo mismo. Resulta que estaba equivocado.
Entonces, ¿por qué ocurrió esta pérdida de rendimiento del 30%? El STL tiene todo en los encabezados, por lo que debería haber sido posible para el compilador comprender todo lo que se requería.
Pensé que es en cómo el bucle inicializa todos los valores al constructor predeterminado. Entonces realicé una prueba:
Los resultados fueron como sospechaba:
Esta es claramente la fuente de la desaceleración, el hecho de que el vector utiliza el constructor de copia para inicializar los elementos de un objeto construido por defecto.
Esto significa que el siguiente orden de pseudooperación ocurre durante la construcción del vector:
Lo cual, debido al constructor de copia implícita hecho por el compilador, se expande a lo siguiente:
Por lo que el defecto
Pixel
sigue siendo un-inicializado, mientras que el resto se inicializa con el valor por defectoPixel
's un-inicializado valores.En comparación con la situación alternativa con
New[]
/Delete[]
:Todos se dejan a sus valores no inicializados, y sin la doble iteración sobre la secuencia.
Armado con esta información, ¿cómo podemos probarlo? Intentemos sobreescribir el constructor de copia implícita.
¿Y los resultados?
En resumen, si está haciendo cientos de vectores muy a menudo: reconsidere su algoritmo .
En cualquier caso, la implementación de STL no es más lenta por alguna razón desconocida, solo hace exactamente lo que le pides; esperando que sepas mejor.
fuente
Intente deshabilitar los iteradores marcados y compilar en modo de lanzamiento. No debería ver mucha diferencia de rendimiento.
fuente
#define _SECURE_SCL 0
. Eso hizoUseVector
alrededor de 4 segundos (similar algcc
siguiente) pero aún así es el doble de lento.-O3
._HAS_ITERATOR_DEBUGGING
está deshabilitado en la versión de lanzamiento: msdn.microsoft.com/en-us/library/aa985939(VS.80).aspxEl STL de GNU (y otros), dado
vector<T>(n)
, por defecto construye un objeto prototipoT()
(el compilador optimizará el constructor vacío), pero luego los STL toman una copia de cualquier basura que haya quedado en las direcciones de memoria ahora reservadas para el objeto.__uninitialized_fill_n_aux
que bucles que completan copias de ese objeto como los valores predeterminados en el vector. Entonces, "mi" STL no está construyendo en bucle, sino construyendo luego en bucle / copia. Es contrario a la intuición, pero debería haberlo recordado cuando comenté una pregunta reciente de stackoverflow sobre este mismo punto: la construcción / copia puede ser más eficiente para los objetos contados de referencia, etc.Entonces:
o
es, en muchas implementaciones de STL, algo como:
El problema es que la generación actual de optimizadores de compiladores no parece funcionar a partir de la idea de que temp es basura no inicializada, y no puede optimizar el bucle y las invocaciones de constructor de copia predeterminadas. Podría argumentar de manera creíble que los compiladores no deberían optimizar esto, ya que un programador que escribe lo anterior tiene una expectativa razonable de que todos los objetos serán idénticos después del ciclo, incluso si es basura (advertencias habituales sobre 'idéntico' / operador == vs memcmp / operator = etc aplica). No se puede esperar que el compilador tenga ninguna idea adicional sobre el contexto más amplio de std :: vector <> o el uso posterior de los datos que sugeriría que esta optimización es segura.
Esto puede contrastarse con la implementación directa más obvia:
Que podemos esperar que un compilador optimice.
Para ser un poco más explícito sobre la justificación de este aspecto del comportamiento del vector, considere:
Claramente, es una gran diferencia si hacemos 10000 objetos independientes versus 10000 que hacen referencia a los mismos datos. Existe un argumento razonable de que la ventaja de proteger a los usuarios ocasionales de C ++ de hacer accidentalmente algo tan costoso supera el costo muy pequeño del mundo real de la construcción de copias difíciles de optimizar.
RESPUESTA ORIGINAL (para referencia / dar sentido a los comentarios): No hay posibilidad. vector es tan rápido como una matriz, al menos si reserva el espacio con sensatez. ...
fuente
La respuesta de Martin York me molesta porque parece un intento de rozar el problema de inicialización debajo de la alfombra. Pero tiene razón al identificar la construcción redundante predeterminada como la fuente de problemas de rendimiento.
[EDITAR: la respuesta de Martin ya no sugiere cambiar el constructor predeterminado.]
Para el problema inmediato en cuestión, podría llamar a la versión de 2 parámetros del
vector<Pixel>
ctor:Eso funciona si desea inicializar con un valor constante, que es un caso común. Pero el problema más general es: ¿cómo se puede iniciar de manera eficiente con algo más complicado que un valor constante?
Para esto, puede usar a
back_insert_iterator
, que es un adaptador iterador. Aquí hay un ejemplo con un vector deint
s, aunque la idea general funciona igual de bien paraPixel
s:Alternativamente, podría usar
copy()
o entransform()
lugar degenerate_n()
.La desventaja es que la lógica para construir los valores iniciales debe trasladarse a una clase separada, lo que es menos conveniente que tenerlo en su lugar (aunque las lambdas en C ++ 1x lo hacen mucho más agradable). También espero que esto aún no sea tan rápido como una
malloc()
versión no STL basada en la base, pero espero que esté cerca, ya que solo hace una construcción para cada elemento.fuente
Los vectores también están llamando constructores de píxeles.
Cada uno está causando casi un millón de corridas que estás cronometrando.
editar: luego está el bucle externo 1 ... 1000, ¡así que haz que mil millones de llamadas ctor!
Edición 2: sería interesante ver el desmontaje del caso UseArray. Un optimizador podría optimizar todo, ya que no tiene otro efecto que no sea quemar la CPU.
fuente
Así es como funciona el
push_back
método en vector:Después de llamar a
push_back
X artículos:Repetir. Si no tienes
reserving
espacio, definitivamente será más lento. Más que eso, si es costoso copiar el artículo, entonces 'push_back' así te va a comer vivo.En cuanto a lo de la
vector
matriz versus, voy a tener que estar de acuerdo con las otras personas. Ejecútelo en la versión, active las optimizaciones y coloque algunas banderas más para que la gente amigable de Microsoft no lo haga.Una cosa más, si no necesita cambiar el tamaño, use Boost.Array.
fuente
reserve
como debería.push_back
Ha amortizado el tiempo constante. Parece que estás describiendo un proceso O (N). (Los pasos 1 y 3 parecen completamente fuera de lugar). Lo que hacepush_back
lento para OP es la verificación de rango para ver si la reasignación debe suceder, actualizar los punteros, la verificación contra NULL dentro de la ubicaciónnew
y otras pequeñas cosas que normalmente se ahogan por El trabajo real del programa.reserve
ya que todavía tiene que hacer esa verificación (si necesita reasignarse) en cada unopush_back
.vector
realiza una funcionalidad de cambio de tamaño, es simplemente "magia". Aquí, déjenme aclararlo un poco más.Algunos datos del generador de perfiles (el píxel está alineado a 32 bits):
Paja
En
allocator
:vector
:formación
La mayor parte de la sobrecarga está en el constructor de copia. Por ejemplo,
Tiene el mismo rendimiento que una matriz.
fuente
pixels.size()
se romperá.Mi laptop es Lenova G770 (4 GB de RAM).
El sistema operativo es Windows 7 de 64 bits (el que tiene una computadora portátil)
El compilador es MinGW 4.6.1.
El IDE es Code :: Blocks .
Pruebo los códigos fuente de la primera publicación.
Los resultados
Optimización de O2
UseArray completado en 2.841 segundos
UseVector completado en 2.548 segundos
UseVectorPushBack completado en 11.95 segundos
Todo se completó en 17.342 segundos
pausa del sistema
Optimización de O3
UseArray completado en 1.452 segundos
UseVector completado en 2.514 segundos
UseVectorPushBack completado en 12.967 segundos
Todo se completó en 16.937 segundos
Parece que el rendimiento del vector es peor con la optimización de O3.
Si cambia el bucle a
La velocidad de la matriz y el vector bajo O2 y O3 son casi iguales.
fuente
Un mejor punto de referencia (creo que ...), el compilador debido a las optimizaciones puede cambiar el código, porque los resultados de los vectores / matrices asignados no se usan en ninguna parte. Resultados:
Compilador:
UPC:
Y el codigo:
fuente
Hice algunas pruebas exhaustivas que quería por un tiempo ahora. Bien podría compartir esto.
Esta es mi máquina de arranque dual i7-3770, 16GB Ram, x86_64, en Windows 8.1 y Ubuntu 16.04. Más información y conclusiones, comentarios a continuación. Probado tanto en MSVS 2017 como en g ++ (tanto en Windows como en Linux).
Programa de prueba
Resultados
Notas
std::sort()
(puede verlo comentado) pero las eliminé más tarde porque no hubo diferencias relativas significativas.Mis conclusiones y observaciones
std::array
las variaciones de tiempo entre ejecuciones consecutivas, mientras que otras, especialmente las estructuras std :: data, variaron enormemente en comparaciónstd::array
y matrices de estilo c más rápido en Windows sin optimizaciónVeredicto
Por supuesto, este es el código para una compilación optimizada. Y como la pregunta era sobre
std::vector
entonces, sí, ¡es mucho! más lento que las matrices simples (optimizado / no optimizado). Pero cuando está haciendo un punto de referencia, naturalmente desea producir código optimizado.Sin embargo, la estrella del espectáculo para mí ha sido
std::array
.fuente
Con las opciones correctas, los vectores y las matrices pueden generar asm idénticos . En estos casos, son, por supuesto, la misma velocidad, porque obtienes el mismo archivo ejecutable de cualquier manera.
fuente
Por cierto, la ralentización de su visión en las clases usando el vector también ocurre con tipos estándar como int. Aquí hay un código multiproceso:
El comportamiento del código muestra que la instanciación del vector es la parte más larga del código. Una vez que atraviesas el cuello de la botella. El resto del código se ejecuta extremadamente rápido. Esto es cierto sin importar cuántos hilos esté ejecutando.
Por cierto, ignore el número absolutamente loco de incluye. He estado usando este código para probar cosas para un proyecto, por lo que el número de incluye sigue creciendo.
fuente
Solo quiero mencionar que vector (y smart_ptr) es solo una capa delgada agregada sobre matrices sin formato (y punteros sin formato). Y, en realidad, el tiempo de acceso de un vector en memoria continua es más rápido que la matriz. El siguiente código muestra el resultado de inicializar y acceder al vector y a la matriz.
El resultado es:
Por lo tanto, la velocidad será casi la misma si la usa correctamente. (como otros mencionaron usando reserve () o resize ()).
fuente
Bueno, porque vector :: resize () procesa mucho más que la asignación de memoria simple (por malloc).
Intente poner un punto de interrupción en su constructor de copias (¡defínalo para que pueda tener un punto de interrupción!) Y ahí va el tiempo de procesamiento adicional.
fuente
Tengo que decir que no soy un experto en C ++. Pero para agregar algunos resultados de experimentos:
compilar: gcc-6.2.0 / bin / g ++ -O3 -std = c ++ 14 vector.cpp
máquina:
OS:
Salida:
Aquí lo único que me parece extraño es el rendimiento de "UseFillConstructor" en comparación con "UseConstructor".
El código:
Por lo tanto, el "valor" adicional proporcionado ralentiza bastante el rendimiento, lo que creo que se debe a la llamada múltiple para copiar el constructor. Pero...
Compilar:
Salida:
Entonces, en este caso, la optimización de gcc es muy importante, pero no puede ayudarlo mucho cuando se proporciona un valor por defecto. Esto, en realidad, va en contra de mi matrícula. Esperemos que ayude al nuevo programador cuando elija qué formato de inicialización de vector.
fuente
Parece depender de los indicadores del compilador. Aquí hay un código de referencia:
Diferentes indicadores de optimización dan diferentes respuestas:
Sus resultados exactos variarán, pero esto es bastante típico en mi máquina.
fuente
En mi experiencia, a veces, solo a veces,
vector<int>
puede ser muchas veces más lento queint[]
. Una cosa a tener en cuenta es que los vectores de vectores son muy diferentesint[][]
. Como los elementos probablemente no son contiguos en la memoria. Esto significa que puede cambiar el tamaño de diferentes vectores dentro del principal, pero es posible que la CPU no pueda almacenar elementos en caché tan bien como en el caso deint[][]
.fuente