2009-03-06 16 views
5

Tengo una pregunta sobre std :: vector.Vector limpia cada iteración de bucle. ¿Cuál es la forma más eficiente de memoria?

Tengo un algoritmo muy intensivo en memoria en el que supongo que predecir los tamaños de vector y reservar suficiente memoria para los vectores de antemano me ayudará mucho a reducir el uso de memoria.

Cuál de los siguientes es mejor:

for (...) { 
    std::vector<Type> my_vector; 
    my_vector.reserve(stuff_count); 
    // Do stuff , and append stuff to my_vector. 
} 

O esto:

std::vector my_vector; 
for (...) { 
    my_vector.clear(); 
    my_vector.reserve(stuff_count); 
    // Do stuff , and append stuff to my_vector. 
} 

por favor dígame qué es lo mejor, o si hay una mejor manera de hacer las cosas.

¡Muchas gracias de antemano!

+0

Esto no es una pregunta de tipo de opinión. Debería medir la diferencia para su sistema particular. –

Respuesta

11

Con la primera variante reasigna el búfer del vector en cada iteración, que suele ser bastante costoso. Con la segunda variante, solo reasignas ocasionalmente. La segunda variante es mejor, ya que la velocidad es una prioridad para ti.

No está claro por su parte de dónde se conoce la cantidad de elementos. Tal vez incluso pueda calcular rápidamente la cantidad máxima de elementos para todas las iteraciones, establecer que sea el tamaño del búfer y no tener reasignaciones.

+0

que suele ser bastante costoso: es una afirmación audaz sin perfiles. El asignador de memoria C++ está diseñado exactamente para este tipo de situación, así que lo dudo (pero incluso esa afirmación es audaz y necesita ser probada). –

+0

Bueno, una vez tuvimos que hacer un perfil en una situación similar. Dichas reasignaciones en casos extremos fueron responsables de alrededor del 95% del tiempo: se asignó un buffer, se copiaron los datos, se analizaron brevemente y luego se descartó el buffer. Eso fue bastante sorprendente. – sharptooth

+0

Esto lleva a la conclusión de que si uno quiere una ejecución rápida, debería evitar reasignaciones innecesarias. – sharptooth

5

El segundo podría ser un poco más rápido, pero el primero me parece más limpio.

+0

Clean está bien, pero en mi situación, limpiar no importa ya que mi algoritmo necesita tanta optimización como sea posible. Mis pruebas no optimizadas podrían usar memoria de 10GB sin problema. – Nailer

+0

Entonces no deberías estar haciendo preguntas como esta (la opinión de todos puede ser/estar mal). Lo que debe hacer es perfilar el código y cronometrarlo en un conjunto de datos más pequeño. –

5

Como las diferencias en el código son triviales, ¿por qué no probar ambos enfoques y ver cuál funciona mejor para su aplicación en particular?

1

Depende un poco de cómo se construye/destruye el tipo, diría yo. Si se trata de un POD que no requiere la destrucción, puede omitir la clara(), que llama a todos los destructores en un bucle, y utilizarlo como una matriz estática en su lugar:

std::vector<Type> my_vector(size); 
for (...) 
{ 
    int index = 0; 
    // Do stuff 
    my_vector[index] = some_value; 
} 

(Advertencia: código no probado)

+0

Si es un POD, espero que el vector optimice la destrucción en cualquier caso. Pruébelo antes de sacar conclusiones sobre el rendimiento – jalf

+0

De acuerdo. (con Jalf) –

+0

En teoría, tienes razón, jalf. Toma mi respuesta como una pista de que podrías estar destruyendo muchas cosas, y que probablemente hay algo de trabajo que se puede hacer allí. –

1

... reservar suficiente memoria para los vectores de antemano me va a ayudar mucho con la reducción de uso de la memoria

err ... ¿qué ?! Eso no tiene sentido en absoluto. Reservar memoria no ayuda a reducir el uso de memoria de ninguna manera. Evita la necesidad de una reasignación constante que hace que las cosas sean más rápidas, pero en lo que respecta a uso, no obtiene ningún beneficio.

+0

De hecho, el número de bytes libres será igual, pero el fragmento asignado más grande será más pequeño: la reasignación una y otra vez hasta que obtenga el tamaño correcto eventualmente fragmentará su pila. En el final. – xtofl

+0

Además de eso, los vectores deben tener memoria continua, por lo que si el vector actual no se puede extender más, se debe asignar un bloque completamente nuevo, el vector anterior se debe copiar y desasignar. Temporalmente usando la memoria (de mayor tamaño + nuevo) Si tiene grandes requisitos de memoria, esto se vuelve relevante. – Pieter

+0

Los vectores asignan el doble de la memoria que necesitan cuando llama a la función de adición y no hay espacio suficiente para el próximo elemento. Esto significa que si tengo un vector lo suficientemente grande para 100 elementos, cuando agregue el elemento 101, el vector asignará memoria suficiente para 200 elementos. – Nailer

6

Supongo que predecir los tamaños de vector y reservar suficiente memoria para los vectores de antemano me ayudará mucho a reducir el uso de memoria.

Probar y actuar como un ingeniero no una adivina. Crea una prueba y mide la diferencia.

0

Si necesita hacer muchos anexos use std :: deque en lugar de std :: vector y simplemente use "push_back".

0

¿qué tal?

std::vector<DataType> my_vector; 
my_vector.resize(sizeof(yourData)); 
memcpy(reinterpret_cast<char*>(&my_vector), &yourData, sizeof(yourData)); 
+0

¿Por qué no std :: copy()? –

1

El segundo se utilizará la memoria máxima de todos los usos de la misma a través del bucle, es decir, el tamaño máximo de tipos de stuff_count. std::vector::clear() does not necessarily free memory. Es decir, si llama al std::vector::capacity() antes y después de std::vector::clear(), una implementación estándar conforme podría devolver el mismo valor.

En el mejor de los casos, reducirá el número de veces que asigna memoria con el esquema anterior. Pero ciertamente no reducirá la huella de memoria en ningún momento. Si desea reducir la cantidad reservada de la memoria, se debe utilizar el lenguaje de intercambio de vectores:

std::vector<type>().swap(my_vector); 
my_vector.reserve(stuff_count); 

O su primera solución, ya que el efecto general será el mismo.

Cuestiones relacionadas