2010-08-30 14 views
5

Necesito diseñar (y codificar, en algún momento) una clase de cadena "personalizada" en C++. Me preguntaba si podría informarme sobre cualquier problema de documentación y diseño, principalmente, y posibles peligros de los que debería tener conocimiento. Los enlaces son muy bienvenidos, como lo son la identificación de problemas (si los hay) con las librerías de cadenas actuales (Qstring, std :: string y las demás).Diseñando una clase de cadena en C++

Gracias.

+7

¿Cuáles son los requisitos de esta cadena y por qué no se puede usar syd:; string o QString, etc.? Estos requisitos tienen que comenzar la investigación – Mark

+0

La mayoría de los programas en C++ se basan en la biblioteca estándar. Si no puede usarlo, esa es una restricción muy importante que debe establecer (y justificar) por adelantado. – Potatoswatter

+0

* por qué * no puedes usar ninguna de las implementaciones de cadenas existentes? – knittl

Respuesta

14

A pesar de las críticas, creo que esta es una pregunta válida.

El std::string no es una panacea. Parece que alguien tomó la clase de un OO puro y la descargó en C++, que probablemente sea el caso.

Consejo 1: Prefiero métodos no amigo no miembros

Ahora que esto se dice, en esta hora de internacionalización, desde luego aconsejaría a diseñar una clase que apoyaría Unicode. Y digo Unicode, no UTF-8 o UTF-16. No encaja (creo) idear una clase que contenga los datos en una codificación determinada. Puede proporcionar métodos para luego generar la información en varios formatos.

Consejo 2: Soporte Unicode

Entonces, hay una serie de puntos en los esquemas de asignación de memoria:

    Optimización
  • pequeña cadena: la clase contiene el espacio pre-asignado para algunos caracteres (una docena o dos), y así evitar la asignación de montón para esos
  • Copiar al escribir: las diversas cadenas comparten un búfer para que la copia sea barata, cuando una cadena necesita modificar su contenido, copia el búfer si no es el único dueño -> el problema es que multihilo supone cargas aquí y que ha sido mostró que para una técnica de uso general esta sobrecarga podría achicar la copia de coste real
  • inmutabilidad: "nuevos" lenguajes como Java, C# o Python utilizar cadenas inmutables. Piense en ello como un conjunto de cadenas, todas las cadenas que contengan "Fooo" apuntarán al mismo buffer. Tenga en cuenta que estos lenguajes son compatibles con la recolección de basura, que más bien ayuda aquí.

elegiría personalmente la "Optimización de cadena pequeña" aquí (aunque no es exclusiva con los otros dos), simplemente porque es más fácil de implementar y de hecho en caso de que (coste asignación del montón, localidad de temas de referencia) beneficiarse.

Las otras dos técnicas son algo complejas frente a la multitracción, y es probable que sean propensas a errores y que no produzcan ningún beneficio real a menos que sean cuidadosamente elaboradas.

Y eso trae mi último consejo:

Consejo 3: no implementan interno de bloqueo en un intento de soporte multihilo

Se retrasará la clase cuando se utiliza en contexto y no SingleThreaded rinde tanto beneficio como piensas cuando se usa en MultiThreaded.

Finalmente, tal vez pueda encontrar algo que se adapte a sus gustos (u obtenga algunos indicadores) navegando por el código existente. No prometo a exponer interfaces "suaves", aunque:

  • UCI UnicodeString: soporte Unicode, al menos
  • std::string: más de 100 métodos miembros (contando las distintas sobrecargas)
  • llvm StringRef: observar cómo muchos algoritmos se implementan como métodos miembros: '(
+2

Toca muchos problemas, y la pregunta se acredita de una manera que el otro no se molestó en hacerlo. Pero, cualquiera que esté considerando volver a implementar una cadena probablemente tenga algunos requisitos de rendimiento muy específicos, por lo que es cuestionable hacer una recomendación general para el soporte de Unicode. Las funciones de no amigos que no son miembros han causado furor con los problemas de diseño, mientras que el usuario final prefiere las API totalmente desarrolladas. Muchos como Alexandrescu han encontrado compromisos en los que un núcleo de funciones se coloca en una plantilla que desarrolla una interfaz std :: string. La interoperabilidad es valiosa. –

+0

@Tony: la idea principal detrás de no amigos no miembros es minimizar el número de métodos que realmente necesitan conocer las partes internas, aún así considero importante entregarlas dentro del mismo archivo de encabezado. Para el soporte de 'Unicode', acepto que soy parcial, pero tener que" internacionalizar "una biblioteca que no admite Unicode desde el principio es extremadamente tedioso:/¿Tiene un enlace al compromiso de Alexandrescu? Me temo que me perdí eso. –

+1

Una lectura interesante y consejos inusualmente sensatos para C++. –

0

El mundo no necesita otra clase de cadena. ¿Es esta tarea? Si no, use std::string.

+8

Lo siento, si hago una pregunta es porque necesito una respuesta, no un consejo. –

+1

Creo que la palabra clave en el OP es "personalizada". Supongo que este debería hacer algo que una clase de cadena estándar no haría. –

+2

... ¡es la respuesta correcta! – Johnsyweb

3

Effective STL por Scott Meyers tiene alguna discusión interesante acerca de las posibles técnicas de implementación std::string, aunque cubre cuestiones bastante avanzadas como el copy-on-write y el recuento de referencias.

2

Dependiendo de qué es la "personalización" (por ejemplo, un asignador personalizado), puede hacerlo a través de un parámetro de plantilla de la clase std :: basic_string.

2

Herb Sutter ofrece una muestra de una clase de cadena personalizada en el GotW #29. Podrías usarlo para el comienzo.

1

Desde un punto de propósito general de vista de una 'nueva' clase string idealmente combinado los aspectos positivos de std :: string, CString, QString y otros unos pocos puntos. en orden aleatorio:

  • MFC CString admite su uso en funciones tipo printf debido a una implementación muy específica. Si necesita o desea esta característica, le recomiendo comprar el libro "MFC Internals" de George Sheperd. Aunque el libro es de 1996 (!) Su descripción de cómo se implementa CString debería valer la pena. http://www.amazon.com/MFC-Internals-Microsoft-Foundation-Architecture/dp/0201407213/ref=sr_1_1?ie=UTF8&s=books&qid=1283176951&sr=8-1
  • Compruebe que la clase string juega muy bien con todas las interfaces que va a utilizar con iostreams (API, de Windows, printf *, etc.)
  • No apunte para la ayuda completa de Unicode (como en: el cotejo, grafema clusters, ...) ya que eso significará que tu clase nunca se terminará, pero considera convertirla en una clase wchar_t con opciones de conversión.
  • Considere hacer que el ctor/función que crea sus objetos de cadena desde char * siempre tome la codificación específica de las matrices de caracteres. (Puede ser útil en entornos combinados de UTF-8/otros juegos de caracteres.)
  • Mire la interfaz completa de CString y en la interfaz estándar de std: string y decida qué va a necesitar y qué puede omitir.
  • Mire QString para ver lo que los otros dos se pierden.
  • Haz no proporcionan la conversión implícita ni a char/wchar_t *
  • considerar la adición de funciones de conversión convenientes a/de los tipos numéricos.
  • ¡No escriba una clase de cuerda sin un conjunto completo de pruebas de unidad detalladas!
0

El problema con std :: string es ... que no puede cambiarlo. A veces necesita los principios básicos de std :: string, pero no está de acuerdo con la implementación de su biblioteca C++.

Como ejemplo, el recuento de referencias seguro para hilos implica muchas operaciones de bloqueo (o al menos bloqueadas).Además, si la mayoría de sus cadenas son cortas (porque sabe que este será el caso), es posible que desee una clase de cadena que esté optimizada para ese caso de uso.

Así que incluso si le gusta la API std :: string, o al menos ha aprendido a vivir con ella, hay espacio para 'implementaciones de la competencia' que son más o menos workalikes.

A PowerDNS le encantaría tener uno, ya que actualmente pasamos muchos nombres de host dns, y la gran mayoría de ellos caben en un búfer fijo de 25 bytes, lo que aliviaría una gran cantidad de presión nueva/eliminar.