2011-04-23 30 views
5

Estoy tratando de aprender un poco más sobre las cadenas de C++.Comprender la eficacia de std :: string

consideran

const char* cstring = "hello"; 
std::string string(cstring); 

y

std::string string("hello"); 

Estoy en lo cierto al suponer que tanto la tienda "hola" en la sección .data de una aplicación y los bytes se copian a otra área en la heap donde el puntero administrado por std :: string puede acceder a ellos?

¿Cómo podría almacenar eficientemente una cuerda realmente larga? Estoy pensando en una aplicación que lee datos de un flujo de socket. Me temo que la concatenación muchas veces. Me podría imaginar usando una lista vinculada y atravesar esta lista.

¡Las cuerdas me han intimidado por demasiado tiempo!

Cualquier enlace, consejos, explicaciones, más detalles, sería extremadamente útil.

+0

¿Cuánto tiempo es realmente realmente largo? 10 MB? 20 tal vez? ¿O te refieres a algo así como 10 GB? Las computadoras tienen gigabytes de RAM en estos días. –

+0

Pensaba más como 10-100 MB. Sin embargo, esta fue una pregunta abierta, así que no dude en explicar cualquiera =). Estoy bastante seguro de que debido a la administración de la memoria del sistema operativo no puede asignar 10 GB de memoria contigua. Supongo que se necesitaría una lista para tal tamaño. – flumpb

+1

@kispit - En mi máquina de 64 bits puedo asignar memoria hasta que el archivo de intercambio llene el disco duro. ¡Decenas de GB no es un problema! –

Respuesta

2

He almacenado cadenas en la gama de 10 o 100 de MB sin problemas. Naturalmente, estará limitado principalmente por su espacio de memoria/dirección disponible (contiguo).

Si va a anexar/concatenar, hay algunas cosas que pueden ayudar a la eficiencia: si es posible, intente utilizar la función de miembro reserve() para asignar espacio previamente, incluso si tiene un una idea aproximada de cuán grande podría ser el tamaño final, se ahorraría de reasignaciones innecesarias a medida que la cuerda crezca.

Además, muchas implementaciones de cadenas usan "crecimiento exponencial", lo que significa que crecen en un porcentaje, en lugar de tamaño de bytes fijo. Por ejemplo, podría simplemente duplicar la capacidad cada vez que se necesita espacio adicional. Al aumentar el tamaño exponencialmente, se vuelve más eficiente realizar muchas concatenaciones. (Los detalles exactos dependerán de la versión de STL.)

Por último, otra opción (si la biblioteca soporta) es utilizar cuerda <> plantilla: Las cuerdas son similares a cuerdas, excepto que son mucho más eficiente cuando se realizan operaciones en cadenas muy grandes. En particular, "las cuerdas se asignan en trozos pequeños, lo que reduce significativamente los problemas de fragmentación de la memoria introducidos por los bloques grandes". Algunos detalles adicionales en SGI's STL guide.

+0

Voy a echarle un vistazo a la cuerda, gracias. – flumpb

0

No creo que la eficiencia sea el problema. Ambos funcionarán lo suficientemente bien.

El factor decisivo aquí es el encapsulado. std::string es una abstracción mucho mejor que char * podría ser alguna vez. Encapsular la aritmética del puntero es algo bueno.

Mucha gente pensó largo y tendido en crear std::string. Creo que no usarlo por razones de eficiencia infundadas es una tontería. Atenerse a la mejor abstracción y encapsulación.

+1

No creo que no sea razonable preocuparse por la eficiencia con el tipo de tamaño de datos del que estamos hablando; 'strcat' lleva a una solución O (n^2) garantizada que puede ser lenta. Hay una buena posibilidad de que 'string.append' pueda ser O (n), el estándar incluso podría garantizarlo. –

+0

El hecho de que muchas personas pensaran largo y tendido sobre std :: string desafortunadamente no habla de su ventaja ... Es una de las partes más criticadas de STL y por una buena razón, creo. Otros idiomas funcionan mejor para cadenas. –

+0

@kotlinski: Me gustaría leer algunas críticas de std :: string. ¿Tienes algún enlace? –

0

Como usted probablemente sabe, an std::string is really just another name for basic_string<char>.

Dicho esto, ellos son un contenedor de secuencias y la memoria se asignarán de forma secuencial. Es posible obtener excepciones de std :: string si intenta hacer una más grande que la memoria contigua disponible que puede asignar.Este umbral suele ser considerablemente menor que la memoria total disponible debido a la fragmentación de la memoria.

He visto problemas al asignar memoria contigua al intentar asignar, por ejemplo, grandes búferes 3D contiguos para imágenes. Pero estos problemas no comienzan a suceder al menos en el orden de los 100 MB más o menos, al menos en mi experiencia, en Windows XP Pro (por ejemplo).

¿Son sus cadenas tan grandes?

2

Como está leyendo la cadena desde un socket, puede reutilizar los mismos almacenamientos intermedios de paquetes y encadenarlos para representar la cadena enorme. Esto evitará cualquier copia innecesaria y es probablemente la solución más eficiente posible. Me parece recordar que la biblioteca ACE proporciona dicho mecanismo. Trataré de encontrarlo.

EDITAR: ACE tiene ACE_Message_Block que le permite almacenar mensajes grandes en una lista enlazada. Casi necesita leer los libros de programación en red de C++ para dar sentido a esta biblioteca colosal. Los tutoriales gratuitos en el sitio web de ACE realmente apestan.

Apuesto Boost.Asio debe ser capaz de hacer lo mismo que los bloques de mensajes de ACE. Boost.Asio ahora parece tener una mayor capacidad de memoria que ACE, por lo que sugiero buscar primero una solución dentro de Boost.Asio. Si alguien puede informarnos sobre una solución de Boost.Asio, ¡sería genial!


Es cuestión de tiempo que trata de escribir una aplicación cliente-servidor simple usando Boost.Asio para ver lo que todo el alboroto.

+0

Voy a ver más sobre esto, muchas gracias por la respuesta – flumpb