c++ performance stdstring compound-assignment

c++ - Diferencia entre la cadena+= s1 y la cadena=cadena+s1



performance stdstring (4)

Para los tipos incorporados a += b es exactamente lo mismo que a = a + b , pero para las clases, esos operadores están sobrecargados y llaman a diferentes funciones.
En su ejemplo, fans = fans + s[i] crea una cadena temporal y la asigna (mueve) a los fans , pero los fans += s[i] no crean esa temporal, por lo que puede ser más rápido.

Uno de mis programas excede el límite de tiempo cuando uso fans = fans + s[i] , mientras que cuando uso fans += s[i] , se está aceptando ... ¿Por qué sucede esto? Para explicar más, los fanáticos son una cadena y s también es una cadena, así que mientras iteramos sobre la cadena, quiero solo algunos caracteres de s, así que estoy creando una nueva cadena. Ahora hay dos maneras en las que puedo agregar caracteres a mi nueva cadena. aficionados. El problema se menciona a continuación.

fans = fans + s[i]; // gives Time limit exceeded fans += s[i]; // runs successfully


Para los tipos fundamentales, a = a + b y a += b significan lo mismo.

Para tipos de clase arbitrarios, a = a + b y a += b no están relacionados; buscan diferentes operadores, y esos operadores pueden hacer cosas arbitrarias. El hecho de que no estén realmente relacionados es el olor a código, un signo de un problema de diseño.

a = a + b convierte en operator=( a, operator+( a, b ) ) aproximadamente; las reglas de búsqueda reales son un poco más complejas (involucran operadores miembros y operadores no miembros, y el hecho de que = no tiene un operador no miembro, etc.), pero ese es su núcleo.

a += b convierte en operator+=( a, b ) en un sentido similar.

Ahora, es un patrón común para implementar + en términos de += ; Si haces esto, obtienes:

a = a + b

se convierte en

a = ((auto)(a) += b);

donde (auto) es el nuevo c ++ 20 / c ++ 23 "crear una copia temporal del argumento" característica.

Fundamentalmente, a+=b puede reutilizar el contenido de a directamente, mientras que a = a + b no puede; en el momento a+b se evalúa a a+b , no se sabe que pronto se sobrescribirá.

Algunas bibliotecas tratan esto utilizando una técnica conocida como "plantillas de expresión"; a+b no es un valor, sino una descripción en tiempo de compilación de la expresión a+b , que cuando se asigna a a se usa para rellenar a con datos. Con las plantillas de expresión, se elimina el problema fundamental de a+=b sabe más que a=a+b .

Ahora, para std::string específicamente, a+b crea un objeto de cadena temporal, luego a=(a+b) mueve a a (puede reutilizar el búfer del objeto de cadena temporal o el búfer de a , el estándar es silencio sobre este asunto).

a+=b debe reutilizar cualquier exceso de capacidad en a búfer. Así que si a.reserve(1<<30) (1 billón), a+=b no puede asignar más.


Si usa fans=fans+s[i] , la cadena se copiará en cada paso de bucle. El nuevo elemento se agregará a la copia de la cadena y el resultado se reasignará a los fans variables. Después de esto, la cadena antigua tendrá que eliminarse porque ya no se hace referencia. Esto lleva mucho tiempo.

Si usa los fans+=s[i] asignación aumentada fans+=s[i] la cadena no se copiará en cada paso de bucle y no es necesario eliminar la variable de referencia ya que aquí no hay ninguna variable de referencia. Esto ahorra mucho tiempo.

Espero que ahora puedas entender !!


std::string tiene miembros operator + y operator += . El primero se implementa generalmente con el segundo por medio de un intermedio temporal. Mirando efectivamente algo como esto (verifique su fuente de implementación si quiere saber exactamente lo que hace el suyo):

/// note reference return type std::string& operator +=(char c) { this->append(c); return *this; } // note value return type std::string operator +(char c) const { std::string tmp = *this; tmp += c; // or just tmp.append(c) directly return tmp; }

La configuración de tmp es costosa. La función general puede (y generalmente se hace) mejor con la semántica de asignación de movimientos al destino final en el lado de la persona que llama, pero el gasto de la temporaria es, sin embargo, aún allí. Hazlo unas cuantas veces y no notarás la diferencia. Hágalo miles, o millones, etc. de veces, y puede significar un mundo de diferencia.