Yo no me preocuparía por eso. Si lo hace en un bucle, las cadenas siempre preasignarán memoria para minimizar las reasignaciones; solo úselas operator+=
en ese caso. Y si lo haces manualmente, algo como esto o más
a + " : " + c
Luego está creando temporales, incluso si el compilador pudiera eliminar algunas copias del valor de retorno. Esto se debe a que en un llamado sucesivamente operator+
no se sabe si el parámetro de referencia hace referencia a un objeto con nombre o un retorno temporal de una operator+
subinvocación. Preferiría no preocuparme por eso antes de no haber perfilado primero. Pero tomemos un ejemplo para demostrarlo. Primero introducimos paréntesis para aclarar el enlace. Pongo los argumentos directamente después de la declaración de función que se usa para mayor claridad. Debajo de eso, muestro cuál es la expresión resultante:
((a + " : ") + c)
calls string operator+(string const&, char const*)(a, " : ")
=> (tmp1 + c)
Ahora, en esa adición, tmp1
es lo que devolvió la primera llamada al operador + con los argumentos mostrados. Suponemos que el compilador es realmente inteligente y optimiza la copia del valor de retorno. Así que terminamos con una nueva cadena que contiene la concatenación de a
y " : "
. Ahora, esto sucede:
(tmp1 + c)
calls string operator+(string const&, string const&)(tmp1, c)
=> tmp2 == <end result>
Compare eso con lo siguiente:
std::string f = "hello";
(f + c)
calls string operator+(string const&, string const&)(f, c)
=> tmp1 == <end result>
¡Está usando la misma función para una cadena temporal y para una cadena con nombre! Entonces el compilador tiene que copiar el argumento en una nueva cadena y agregarlo y devolverlo desde el cuerpo de operator+
. No puede tomar la memoria de un temporal y agregarlo. Cuanto más grande sea la expresión, más copias de cadenas deberán realizarse.
Siguiente Visual Studio y GCC admitirán la semántica de movimiento de c ++ 1x (complementando la semántica de copia ) y las referencias rvalue como una adición experimental. Eso permite averiguar si el parámetro hace referencia a un temporal o no. Esto hará que las adiciones sean increíblemente rápidas, ya que todo lo anterior terminará en una "tubería de adición" sin copias.
Si resulta ser un cuello de botella, aún puede hacerlo
std::string(a).append(" : ").append(c) ...
Las append
llamadas añaden el argumento ay *this
luego devuelven una referencia a sí mismas. Por lo tanto, no se realiza ninguna copia de temporales allí. O alternativamente, operator+=
se puede usar, pero necesitaría paréntesis feos para arreglar la precedencia.