c++ string memory-management stl

c++ - inicialización de std:: string de char*sin copia



memory-management stl (6)

Tengo una situación en la que necesito procesar grandes cantidades de datos (muchos GB) como tales:

  1. construir una cadena grande añadiendo muchas cadenas más pequeñas (C char *)
  2. recortar la cadena
  3. convierta la cadena en una const std :: string de C ++ para procesarla (solo lectura)
  4. repetir

Los datos en cada iteración son independientes.

Mi pregunta es, me gustaría minimizar (si es posible eliminar) el uso de la memoria asignada en el montón, ya que en este momento es mi mayor problema de rendimiento.

¿Hay alguna forma de convertir una cadena C (char *) en una cadena stl C ++ (std :: string) sin requerir que std :: string aloje / copie los datos internamente?

Alternativamente, ¿podría usar stringstreams o algo similar para reutilizar un buffer grande?

Editar: Gracias por las respuestas, para mayor claridad, creo que una pregunta revisada sería:

¿Cómo puedo construir (a través de múltiples enlaces) una cadena stl C ++ de manera eficiente? Y si realiza esta acción en un bucle, donde cada bucle es totalmente independiente, ¿cómo puedo volver a utilizar este espacio asignado?


¿Cada iteración es lo suficientemente independiente como para poder usar la misma cadena std :: para cada iteración? Uno esperaría que su implementación de std :: string sea lo suficientemente inteligente como para reutilizar la memoria si le asigna una const char * cuando se usaba anteriormente para otra cosa.

Asignar un char * en std :: string siempre debe copiar al menos los datos. La administración de la memoria es una de las razones principales para usar std :: string, por lo que no podrá anularla.


En este caso, podría ser mejor procesar el char * directamente, en lugar de asignarlo a std :: string.


En realidad, no puede formar una cadena std :: sin copiar los datos. Un stringstream probablemente reutilizaría la memoria de pasada a pasada (aunque creo que el estándar no dice si realmente tiene que hacerlo), pero aún así no evitaría la copia.

Un enfoque común para este tipo de problema es escribir el código que procesa los datos en el paso 3 para usar un par de iteradores de inicio / final; luego puede procesar fácilmente una std :: string, un vector de caracteres, un par de punteros crudos, etc. A diferencia de pasarle un tipo de contenedor como std :: string, ya no sabría ni importaría cómo se asignó la memoria, ya que todavía pertenecería a la persona que llama. Llevando esta idea a su conclusión lógica es boost::range , que agrega todos los constructores sobrecargados para permitir que la persona que llama simplemente pase una cadena / vector / lista / cualquier tipo de contenedor con .begin () y .end (), o por separado iteradores.

Después de haber escrito su código de procesamiento para trabajar en un rango de iterador arbitrario, podría incluso escribir un iterador personalizado (no tan difícil como suena, básicamente solo un objeto con algunos typedefs estándar, y el operador ++ / * / = / == / ! = sobrecargado para obtener un iterador de solo avance) que se encarga de avanzar al siguiente fragmento cada vez que toca el final del que está trabajando, omitiendo el espacio en blanco (supongo que eso es lo que quiso decir con recorte). Que nunca tuviste que ensamblar toda la cadena contiguamente. Que esto sea o no un triunfo depende de cuántos fragmentos / qué tan grande de fragmentos tenga. Esto es esencialmente lo que la cuerda SGI mencionada por Martin York es: una cadena donde el apéndice forma una lista vinculada de fragmentos en lugar de un buffer contiguo, que por lo tanto es adecuado para valores mucho más largos.

ACTUALIZAR (ya que todavía veo votaciones ascendentes ocasionales sobre esta respuesta):

C ++ 17 introduce otra opción: std::string_view , que reemplazó std :: string en muchas firmas de funciones, es una referencia no propietaria de los datos de un carácter. Es implícitamente convertible desde std :: string, pero también puede construirse explícitamente a partir de datos contiguos pertenecientes a otra parte, evitando la copia innecesaria std :: string impone.


Esta es una respuesta de pensamiento lateral, que no aborda directamente la cuestión, sino que "piensa" a su alrededor. Podría ser útil, podría no ...

El procesamiento de solo lectura de std :: string realmente no requiere un subconjunto muy complejo de las características de std :: string. ¿Existe la posibilidad de que pueda buscar / reemplazar en el código que realiza todo el procesamiento en std :: cadenas, por lo que se necesita algún otro tipo en su lugar? Comience con una clase en blanco:

clase lightweight_string {};

Luego reemplace todas las referencias de std :: string con lightweight_string. Realice una compilación para averiguar exactamente qué operaciones se necesitan en lightweight_string para que actúe como un reemplazo directo. Luego puede hacer que su implementación funcione como lo desee.


Para ayudar con cadenas realmente grandes, SGI tiene la clase Rope en su STL.
No estándar, pero puede ser útil.

http://www.sgi.com/tech/stl/Rope.html

Al parecer, la cuerda está en la próxima versión del estándar :-)
Tenga en cuenta la broma del desarrollador. Una cuerda es una gran cadena. (Jaja) :-)


¿Es posible utilizar una cadena de C ++ en el paso 1? Si usa string::reserve(size_t) , puede asignar un búfer lo suficientemente grande para evitar múltiples asignaciones de montón al agregar las cadenas más pequeñas, y luego puede usar esa misma cadena de C ++ en todos los pasos restantes.

Vea este enlace para más información sobre la función de reserve .