¿Hay una clase de C ++ Biblioteca de plantillas estándar que proporciona la funcionalidad de concatenación de cadenas eficiente, similar a C # 's StringBuilder o de Java StringBuffer ?
c++
stl
string-concatenation
Andrés
fuente
fuente
std::ostringstream
.Respuestas:
NOTA: esta respuesta ha recibido alguna atención recientemente. No estoy abogando por esto como una solución (es una solución que he visto en el pasado, antes de la STL). Es un enfoque interesante y solo debe aplicarse sobre
std::string
ostd::stringstream
si después de perfilar su código descubre que esto mejora.Normalmente uso cualquiera
std::string
ostd::stringstream
. Nunca he tenido ningún problema con estos. Normalmente reservaría algo de espacio primero si supiera de antemano el tamaño aproximado de la cuerda.He visto a otras personas hacer su propio generador de cadenas optimizado en el pasado distante.
Utiliza dos cadenas, una para la mayoría de la cadena y la otra como un área de scratch para concatenar cadenas cortas. Optimiza los agregados al agrupar las operaciones de agregado corto en una cadena pequeña y luego agregar esto a la cadena principal, reduciendo así el número de reasignaciones requeridas en la cadena principal a medida que se hace más grande.
No he requerido este truco con
std::string
ostd::stringstream
. Creo que se usó con una biblioteca de cadenas de terceros antes de std :: string, fue hace mucho tiempo. Si adopta una estrategia como este perfil, su aplicación primero.fuente
scratch
cadena realmente logre nada aquí. El número de reasignaciones de la cadena principal dependerá en gran medida de su tamaño final, no del número de operaciones de adición, a menos que lastring
implementación sea realmente pobre (es decir, no utilice un crecimiento exponencial). Así que "agrupar"append
no ayuda porque una vez que el subyacentestring
es grande, solo crecerá ocasionalmente de cualquier manera. Además de eso, agrega un montón de operaciones de copia redundantes y puede haber más reasignaciones (por lo tanto, llamadas anew
/delete
) ya que está agregando una cadena corta.str.reserve(1024);
que sería más rápido que esta cosaLa forma en C ++ sería usar std :: stringstream o simplemente concatenaciones de cadenas simples. Las cadenas de C ++ son mutables, por lo que las consideraciones de rendimiento de la concatenación son menos preocupantes.
con respecto al formateo, puede hacer el mismo formateo en una secuencia, pero de una manera diferente, similar a
cout
. o puede usar un functor fuertemente tipado que encapsula esto y proporciona una interfaz tipo String.Format, por ejemplo, boost :: formatfuente
StringBuilder
existe es para cubrir la ineficiencia del tipo de cadena básica inmutable de Java . En otras palabras,StringBuilder
es un mosaico, por lo que deberíamos estar contentos de no necesitar tal clase en C ++.O(n)
en general.La
std::string.append
función no es una buena opción porque no acepta muchas formas de datos. Una alternativa más útil es usarstd::stringstream
; al igual que:fuente
std::string
es el equivalente de C ++: es mutable.fuente
Puede usar .append () para simplemente concatenar cadenas.
Creo que incluso podrías hacer:
En cuanto a las operaciones de formateo de C # 's
StringBuilder
, creo quesnprintf
(osprintf
si quieres arriesgarte a escribir un código defectuoso ;-)) en una matriz de caracteres y volver a convertirlo en una cadena es la única opción.fuente
Como
std::string
en C ++ es mutable, puede usar eso. Tiene un+= operator
y unappend
función.Si necesita agregar datos numéricos, use el
std::to_string
funciones.Si desea aún más flexibilidad en la forma de poder serializar cualquier objeto en una cadena, use la
std::stringstream
clase. Pero necesitará implementar sus propias funciones de operador de transmisión para que funcione con sus propias clases personalizadas.fuente
std :: string's + = no funciona con const char * (lo que parece ser "string to add"), por lo que definitivamente usar stringstream es lo más cercano a lo que se requiere: simplemente use << en lugar de +
fuente
Un conveniente generador de cadenas para c ++
Como muchas personas respondieron antes, std :: stringstream es el método de elección. Funciona bien y tiene muchas opciones de conversión y formato. Sin embargo, en mi opinión, tiene un defecto bastante inconveniente: no puedes usarlo como una sola línea o como una expresión. Siempre tienes que escribir:
lo cual es bastante molesto, especialmente cuando quieres inicializar cadenas en el constructor.
La razón es que a) std :: stringstream no tiene operador de conversión a std :: string yb) los operadores << () del stringstream no devuelven una referencia de stringstream, sino una referencia std :: ostream - que no se puede calcular más como una secuencia de cadena.
La solución es anular std :: stringstream y darle mejores operadores de coincidencia:
Con esto, puedes escribir cosas como
incluso en el constructor.
Tengo que confesar que no medí el rendimiento, ya que todavía no lo he usado en un entorno que hace un uso intensivo de la construcción de cadenas, pero supongo que no será mucho peor que std :: stringstream, ya que todo está hecho a través de referencias (excepto la conversión a cadena, pero también es una operación de copia en std :: stringstream)
fuente
std::stringstream
no se comporta de esta manera.El contenedor Rope puede valer si tiene que insertar / eliminar una cadena en el lugar aleatorio de la cadena de destino o para una secuencia de caracteres larga. Aquí hay un ejemplo de la implementación de SGI:
fuente
Quería agregar algo nuevo por lo siguiente:
En un primer intento no pude vencer
std::ostringstream
'soperator<<
eficiencia, pero con más intentos pude hacer un StringBuilder que es más rápido en algunos casos.
Cada vez que agrego una cadena, solo almaceno una referencia en ella en algún lugar y aumento el contador del tamaño total.
La forma real en que finalmente lo implementé (¡Horror!) Es usar un búfer opaco (std :: vector <char>):
para el byte []
para cadenas movidas (cadenas agregadas con
std::move
)std::string
objeto (tenemos propiedad)para cuerdas
std::string
objeto (sin propiedad)También hay una pequeña optimización, si la última cadena insertada se movió, comprueba los bytes libres reservados pero no utilizados y almacena más bytes allí en lugar de usar el búfer opaco (esto es para ahorrar algo de memoria, en realidad lo hace un poco más lento , tal vez dependa también de la CPU, y de todos modos es raro ver cadenas con espacio reservado adicional)
Finalmente, esto fue un poco más rápido que,
std::ostringstream
pero tiene algunas desventajas:ostringstream
¿conclusión? utilizar
std::ostringstream
Ya solucionó el mayor cuello de botella, mientras que obtener pocos puntos porcentuales de velocidad con la implementación de la mina no vale la pena.
fuente