Push_back en bucle contra resize () + iterator

Pregunta simple; ¿Qué es mejor y por qué?

out.resize( in.size() ); T1::iterator outit = out.begin(); for( inIt = in.begin() to end, ++inIt, ++outIt ) *outit = *inIt OR out.erase(); for( inIt = in.begin() to end, ++inIt ) out.push_back( inIt ); 

Supongo que vale la pena evitar la asignación de memoria implícita en push_back, pero quiero estar seguro.

Gracias

EDIT: Gracias por la salida = en sugerencias chicos;). El código real con el que estoy jugando es:

 template//can't stop the browser ignoring th class T1, class T2 in angle brackets bool asciihex( T1& out, const T2& in ) { //out.erase(); out.resize( in.size() / 2 ); if( std::distance( in.begin(), in.end() ) % 2 )//use distance rather than size to minimise the requirements on T2? return false; for( T2::const_iterator it = in.begin(); it != in.end(); it += 2 ) { out.push_back(((( (*it > '9' ? *it - 0x07 : *it) - 0x30) '9' ? *(it+1) - 0x07 : *(it+1)) - 0x30) & 0x000f)); } return true; } template bool asciihex( T1& out, const T2& in ) { size_t size = in.size(); if( size % 2 )//use distance rather than size to minimise the requirements on T2? return false; out.resize( size / 2 ); T1::iterator outit = out.begin(); for( T2::const_iterator it = in.begin(); it != in.end(); it += 2, ++outit ) { *outit = ((( (*it > '9' ? *it - 0x07 : *it) - 0x30) '9' ? *(it+1) - 0x07 : *(it+1)) - 0x30) & 0x000f); } return true; } 

Edición: he marcado push_back como la respuesta, ya que parece ser el consenso y, por lo tanto, más útil para cualquier otra persona con el mismo problema. Sin embargo, he terminado usando el método del iterador ya que una de las clases de contenedor en las que estoy interesado no es compatible con push_back … el kilometraje varía.

El segundo, y si le preocupan las múltiples extensiones, use out.reserve (). La respuesta correcta para agregar a un vector es casi siempre push_back o back_inserter, que evita algunos problemas posibles (garantías de excepción, constructores, escritura más allá del final, por ejemplo) a los que debería prestar atención con otros métodos.

El segundo, siempre que se reserve la capacidad correcta primero.

Un problema que veo (aparte del estilo) es que en la primera, si su asignación de copias se lanza, ha realizado una operación que debería darle una garantía sólida y la usó para no dar ninguna garantía.

Si te interesa preservar, entonces haz:

 out = in; 

Si no lo haces, entonces haz

 std::swap(out, in); 

Si hay diferentes tipos de contenedores, intente esto:

 out.erase(out.begin(), out.end()); // if it's a vector or other contiguous memory container, you'll want to reserve first // out.reserve(in.size()); std::copy(in.begin(), in.end(), back_inserter(out)); 

Entonces, ¿qué está mal con esto?

 out = in; 

¿No crees que tendría el mejor comportamiento posible? Si no lo hace, eso apesta.

Además, sus dos ejemplos de código deben ser

 out.resize( in.size() ); T1::iterator outIt = out.begin(); for( T1::iterator inIt = in.begin(); inIt != in.end(); ++inIt, ++outIt ) *outIt = *inIt; 

y

 out.erase(out.begin(), out.end()); for( T1::iterator inIt = in.begin(); inIt != in.end(); ++inIt ) out.push_back( *inIt ); 

Si está tratando con valores simples como enteros o dobles, no importará (en cuanto al rendimiento) si cambia el tamaño y establece o reserva y push_back.

Si está tratando con objetos más complejos que tienen un constructor significativo, es mejor usar el segundo método basado en push_back.

Si los objetos no tienen un constructor predeterminado significativo, el enfoque push_back es la única técnica que funciona.

Tuve una situación en la que obtuve peor rendimiento en push_back solución basada en push_back en comparación con una que usaba el operador [] en un vector redimensionado. La causa de la diferencia fue la sobrecarga en la verificación de si el vector necesita expandir su capacidad cada vez que estaba haciendo un push_back .

Lo que lo hizo aún peor fue que el comstackdor decidió que no podía push_back la llamada a push_back , pero push_back la lógica de reserva en el método push_back . Esto dio la sobrecarga de una llamada de función y la función invocada era innecesariamente grande. Incluso después de un masaje force_inline, no fue tan rápido como el bucle basado en el operador [].

Un bucle basado en iteradores o el operador [] no hará nada más que escribir el valor, al menos no cuando se trabaja con tipos simples. Si trabaja con tipos más avanzados, el costo del constructor predeterminado al redimensionar el vector puede arruinar las ganancias potenciales.

De todos modos, si su progtwig pasa la mayor parte del tiempo en este tipo de bucle, definitivamente creo que debería evaluar las diferentes soluciones y ver si hay algún rendimiento que ganar al usar una de las soluciones. Si no está gastando una cantidad considerable de su tiempo de ejecución en la función que describió, no debería preocuparse por esta publicación 🙂

Algo similar fue discutido aquí antes.

Prefiero push_back sobre la asignación de arreglos, ya que push_back funcionará con o sin randomaccessiterators. La asignación de matrices los requiere. Si fuerza a los operadores aleatorios ahora, no podrá cambiar fácilmente el contenedor en el futuro. Por supuesto, para evitar problemas de cambio de tamaño, debe llamar vector :: capacidad en lugar de cambiar el tamaño.