sistematizar optimizacion entre ejemplos diferencia ciclos automatizar c++ c++11

c++ - optimizacion - diferencia entre automatizar y sistematizar



¿Es una optimización prematura usar std:: move()? (5)

No estoy seguro de cómo el compilador optimizaría la copia (si es que lo hace) sin std::move() .

Solo un compilador muy inteligente podría optimizar eso, así que si la copia puede ser costosa (por ejemplo, una cadena muy larga), entonces es mejor moverla.

Sin el movimiento, el código es efectivamente una secuencia de llamadas a:

strlen // count "Hello World" malloc // allocate memory for string var strcpy // copy data into var malloc // re-allocate vector free // deallocate old vector malloc // allocate new string strcpy // copy from var to new string free // destroy var

Con el movimiento se convierte en:

strlen // count "Hello World" malloc // allocate memory for string var strcpy // copy data into var malloc // re-allocate vector free // deallocate old vector

En teoría, un compilador inteligente podría hacer esa transformación automáticamente, pero para el compilador ver todas las capas de abstracción introducidas por los constructores y el destructor y las funciones miembro del vector es bastante difícil, demostrando así que el código podría transformarse para eliminar un malloc y free es complicado.

Supongamos que tengo el siguiente código:

int main() { std::vector<std::string> strs; std::string var("Hello World"); // Make some modifications to ''var'' strs.push_back(std::move(var)); }

La parte de la muestra que quiero señalar es el uso de std::move() . Básicamente, estoy preocupado por una copia en la llamada push_back() . Supongamos que la cadena que estoy agregando es realmente grande. Todavía estoy aprendiendo C ++ 11 referencias de valor r, así que no estoy seguro de cómo el compilador optimizaría la copia (si es que lo hace) sin std::move() .

¿Podría alguien explicar si se trata de una optimización prematura (forzando movimientos en todos los casos en los que desea evitar copias, en general)? De ser así, ¿qué patrones debo esperar que siga el compilador (o lo más probable es que siga) que resulten en un movimiento optimizado y automático aquí?

EDITAR

Quiero agregar que entiendo cómo ocurren los movimientos automáticos en los valores de retorno de la función , porque se aplica NRVO / RVO. El ejemplo específico que di aquí no aplicaría RVO, entonces no estoy seguro.


Después de std::move , el objeto original, en este caso var , debe estar en un estado válido pero podría contener cualquier valor, por ejemplo, podría estar vacío.

Si sabe que no va a usar var y solo lo creó para ponerlo en el vector entonces no se trata de una optimización "prematura" como la intención de lo que está tratando de hacer.

vector tiene un nuevo método emplace_back() que es lo mismo pero más claro, y usa forward-arguments (aquí solo haces emplace_back("Hello World") si todo lo que estás haciendo es construirlo). En su caso, ya que está "haciendo algunas modificaciones con var", es poco probable que emplace_back no sea apropiado.

En el viejo C++ puedes optimizar la copia haciendo push_back() en una cadena vacía y luego intercambiándola.


No sé por qué todos te sugieren que uses emplace_back() . El propósito de emplace_back() es evitar las operaciones de copia / movimiento al construir el objeto en su lugar. En este caso, ya ha construido el objeto, por lo que al menos 1 copia / movimiento es inevitable. No hay ninguna ventaja al usar emplace_back() sobre push_back() en este caso.

De lo contrario, estoy de acuerdo con todos los demás que dicen que no es una optimización prematura porque la semántica del movimiento modela lo que estás tratando de hacer más de cerca que hacer una copia del objeto.


Sí, es una optimización prematura si se trata de una optimización prematura.

Déjame elaborar:
La optimización prematura se define por si está optimizando una parte del código que no sabe que es crítico para el rendimiento. Es decir, la optimización prematura nunca se define por el método de optimización, siempre se define por el lugar de optimización y su conocimiento sobre lo que está haciendo.

Ahora, a la conveniencia de optimizar usando std::move() :

Con std::move() evita el trabajo pesado de la construcción de copias, como la asignación de memoria, la desasignación, la copia, la construcción de elementos contenidos, la deconstrucción de elementos contenidos, etc. Eso es bueno. Pero una parte remite: la construcción / destrucción del objeto contenedor.

emplace_back() tiene la virtud de evitar por completo la construcción del objeto temporal. Por lo tanto, siempre que pueda evitar un objeto temporal usando emplace_back() , obtendrá una pequeña ganancia.

Teniendo en cuenta la calidad del código (lectura legibilidad / mantenibilidad): std::move() tiene la desventaja de dejarte un objeto inutilizable, que puede ser una fuente de errores. Esto no ocurre con emplace_back() . Entonces, de nuevo, el último es claramente preferible.

Por supuesto, emplace_back() no se puede usar en todos los contextos que permiten el uso de std::move() . Entonces, si estos son críticos para el rendimiento, std::move() puede ser el camino a seguir. Hay algunos casos de uso muy válidos para la optimización con std::move() . Sin embargo, también puede descubrir que puede escribir el código de una manera que no requiera ninguna construcción de copia / movimiento / emplazamiento. ¡Nunca deje de buscar una mejor solución al optimizar!

Al final, permanece que la validez de optimizar con std::move() depende completamente del contexto: es una buena optimización donde sea que sea una buena optimización.


Las otras respuestas se enfocan demasiado en los aspectos técnicos de la pregunta para mi gusto, así que trataré de dar una respuesta más general.

En resumen: No, usar un "truco" como std :: move en la forma en que se describe en la pregunta no es una optimización prematura. No está bien usar std::move cuando se puede usar, a menos que ya se sepa que el código es crítico para el rendimiento.

La necesidad de evitar la optimización prematura a veces se entiende como "no optimizar, hasta que pueda demostrar que es necesario", pero prefiero leerlo como: "no pierda el tiempo resolviendo problemas a menos que sepa que deben ser resueltos".

Las optimizaciones prematuras requieren un esfuerzo de gasto para optimizar lo que no es necesario optimizar, y generalmente transforman un problema simple en un problema complejo mientras lo hacen. Desde esa perspectiva, clasificaría cualquier reflexión larga de la pregunta en sí misma como una optimización prematura.

Un ejemplo relacionado: las personas que trabajan en el código crítico de rendimiento a menudo pasan los argumentos como referencias const std::string& ( const std::string& ). Debido a que es lo que solían hacer, usarán el mismo patrón en el código que no es crítico para el rendimiento, aunque podrían usar el método de paso a paso ( const std::string , o incluso std::string ). Esa tampoco es una optimización prematura.