2010-10-19 13 views
5

Esa es prácticamente toda la cuestión. Me temo que no conozco plantillas (o C++, realmente), pero sé algoritmos y estructuras de datos (¡incluso algunos OOP! :). De todos modos, para hacer la pregunta un poco más precisa, considere lo que me gustaría ser parte de la respuesta (entre otros no sé de antemano).¿Cómo funciona la clase de cadena en C++ std work

  1. ¿Por qué está codificado como plantilla?
  2. ¿Cómo funciona la plantilla?
  3. ¿Cómo funciona la asignación de memoria?
  4. ¿Por qué (es mejor) que las matrices de caracteres terminados nulos?

Gracias.

+10

¿Tienes un libro en C++? Si no sabes cómo funcionan las plantillas, preguntar por qué una clase las usa parece ser una oportunidad para mí. – GManNickG

+0

http://www.cplusplus.com/reference/string/ es un buen comienzo. – Tristan

+0

¿Es tan difícil de explicar? De acuerdo, tienes que saber explicar esto claramente ... Apuesto a que alguien aquí puede hacerlo sin ser condescendiente. Me pregunto, en realidad, qué pasaría si mis estudiantes vinieran a mí con una pregunta como esa y yo simplemente dijera "ve a aprenderla tú mismo". Chicos ... :) –

Respuesta

15
  1. std::string es en realidad un typedef a un std::basic_string<char>, y en ella se encuentra la respuesta a su # 1 anterior. Es una plantilla para hacer que basic_string funcione con casi cualquier cosa. char, unsigned char, wchar_t, pizza, lo que sea ... string es solo una utilidad del programador que usa char como el tipo de datos, ya que eso es lo que a menudo se desea.

  2. No contestable según lo solicitado. Si está confundido acerca de algo, intente reducirlo un poco.

  3. Hay dos respuestas.Uno, desde el punto de vista de la capa de aplicación, todos los objetos basic_string usan un objeto allocator para realizar la asignación real. Los métodos de asignación pueden variar de una implementación a la siguiente y para diferentes parámetros de plantilla, pero en la práctica usarán new en los niveles inferiores para asignar & administrar el recurso contenido.

  4. Es mejor que meras matrices de caracteres por una amplia variedad de razones.

    • string gerentes la memoria para usted. No tiene que asignar espacio en el búfer cuando agrega o elimina datos en la cadena. Si agrega más de lo que cabe en el búfer asignado actualmente, string lo reasignará detrás de las escenas.

    • En este sentido, string se puede considerar como un tipo de puntero inteligente. Por las mismas razones por las que los punteros inteligentes son mejores que los punteros sin procesar, string s son mejores que las matrices sin procesar.

    • Tipo de seguridad. Esto puede parecer un poco intrincado, pero string usado correctamente tiene mejor seguridad de tipo que los tampones de carbón. Considere un escenario común:

 

#include <string> 
#include <sstream> 
using namespace std; 

int main() 
{ 
    const char* jamorkee_raw = "jamorkee"; 

    char raw_buf[0x1000] = {}; 
    sprintf(raw_buf, "This is my string. Hello, %f", jamorkee_raw); 

    const string jamorkee_str = "jamorkee"; 
    stringstream ss; 
    ss << "This is my string. Hello " << jamorkee_str; 
    string s = ss.str(); 
} 

el tema de seguridad de tipo planteado en el anterior mediante el uso de un char buffer prima ni siquiera es posible cuando se utiliza junto con string corrientes.

+0

¿Qué pasa con el formateo?!?! Graaaargh! –

+2

+1 por respuesta increíble. Simple pero no * demasiado * simple! –

+0

Algo relacionado con los bloques de código después de las listas. :/Aquí está mi intento, no tienes que guardarlo. – GManNickG

0

Un buen recurso gratuito en línea es "Thinking in C++" de Bruce Eckel, cuyo sitio está aquí: http://mindview.net/Books/TICPP/ThinkingInCPP2e.html.

El segundo volumen de su libro gratuito se refleja aquí: http://www.smart2help.com/e-books/ticpp-2nd-ed-vol-two/#_ftnref14. El tercer capítulo trata sobre la clase de cadena, por qué es una plantilla y por qué es útil.

+0

Gracias por el recurso. Realmente no estoy preguntando cómo usarlo, solo cómo se implementa en el nivel más bajo. –

2
  1. string no es la plantilla, string es una especialización de la plantilla basic_string clase para char. Es una plantilla para que, por ejemplo, pueda escribirdedef wstring que se especialice en caracteres anchos y use el mismo código para el valor encapsulado.

  2. Consulte el comentario de @Gman. La reutilización de código en tiempo de compilación, aunque conserva la capacidad de seleccionar casos especiales, es la razón fundamental para las plantillas.

  3. Depende de la implementación. Algunos hacen asignación de instancia única, con copia en escritura. Algunos usan un buffer incorporado para cadenas pequeñas y lo asignan desde el montón solo después de alcanzar un cierto tamaño. Le sugiero que investigue cómo funciona en su compilador al recorrer el constructor y el código de seguimiento en <string>, ya que eso lo ayudará a comprender 2. las manos, que es mucho más valioso que solo leer sobre él (aunque sea un libro u otra lectura). es una gran idea para introducir plantillas).

  4. Porque const char* y el CRT que lo admite es una granja de errores para los incautos. Mira todas las cosas que obtienes gratis con std::string. Además de un whole bunch of Standard C++ algorithms que funciona con string iteradores.

7

Un tiro bastante rápido (y por lo tanto probablemente incompleta) a responder algunas de las preguntas:

  1. ¿Por qué se codifica como una plantilla?

Las plantillas proporcionan la capacidad para que las funciones de clase funcionen en tipos de datos arbitrarios. Por ejemplo, la clase de plantilla basic_string<> puede funcionar en unidades char (que es lo que hace el typedef std::string) o wchar_t unidades (std::wstring) o cualquier tipo POD. El uso de algo que no sea char o wchar_t es inusual (std::vector<> sería más probable que se use), pero existe la posibilidad.

  1. ¿Cómo se hace la asignación de memoria?

Esto no está especificado en la norma. De hecho, la plantilla basic_string<> permite utilizar un asignador arbitrario para la asignación real de la memoria (pero no determina en qué puntos se pueden solicitar las asignaciones). Algunas implementaciones pueden almacenar cadenas cortas en miembros de clase reales, y solo asignar dinámicamente cuando las cadenas crecen más allá de un cierto tamaño. El tamaño solicitado puede ser exactamente lo que se necesita para almacenar la cadena o puede ser un múltiplo del tamaño para permitir el crecimiento sin una reasignación.

Información adicional robado de another SO answer:

Scott Meyer's book, Effective STL, tiene un capítulo sobre las implementaciones std :: string que es una visión digna de las variaciones comunes: "Artículo 15: Tenga en cuenta las variaciones en las implementaciones de cuerda".

Habla de 4 variantes:

  • varias variaciones en una aplicación ref-contados (comúnmente conocido como copia en escritura) - cuando un objeto cadena se copia sin cambios, refcount se incrementa, pero la cadena real los datos no son Ambos objetos apuntan a los mismos datos refregados hasta que uno de los objetos lo modifica, causando una "copia al escribir" de los datos. Las variaciones están en donde se almacenan cosas como el recuento, los bloqueos, etc.

  • una implementación "optimización de cadena corta". En esta variante, el objeto contiene el puntero de costumbre a los datos, la longitud, el tamaño de la memoria intermedia asignada dinámicamente, etc. Pero si la cadena es lo suficientemente corto, utilizará esa zona para mantener la cadena en lugar de asignar dinámicamente una memoria intermedia

  1. ¿Por qué es (no es) mejor que las matrices de cab terminadas nulas?

Una forma la clase string es mejor que una simple matriz terminada en nulo es que la clase gestiona la memoria necesaria, por lo que se reducen defectos que implican errores de asignación o de rueda libre al final de los arrays asignados. Otro beneficio (quizás menor) es que puede almacenar caracteres "nulos" en la cadena. Una desventaja es que tal vez haya algo de sobrecarga, especialmente que casi tiene que depender de la asignación de memoria dinámica para la clase de cadena. En la mayoría de los escenarios que probablemente no sea un problema importante, en algunas configuraciones (sistemas integrados, por ejemplo) puede ser un problema.

+0

Buen complemento. Gracias. –

+0

No tan rápido, no tan incompleto. Buena respuesta. :) –

+0

Iba a tratar de decir algo sobre "¿Cómo funciona la plantilla?" pregunta, pero decidí punt. –

2

¿Por qué se codifica como una plantilla?

Varias personas han dado la respuesta que el tener std::basic_string ser una plantilla significa que usted puede tener ambas cosas std::basic_string<char> y std::basic_string<wchar_t>. Lo que nadie ha explicado es por qué C y C++ tienen múltiples tipos de caracteres en primer lugar.

C, especialmente en sus primeras versiones, era minimalista sobre tipos de datos. ¿Por qué tener bool cuando los números enteros 0 y 1 funcionan bien? ¿Y por qué tienen distintos tipos de "byte" y "personaje" cuando ambos son 8 bits?

El problema es que 8 bits se limita a 256 caracteres, lo cual es adecuado para un lenguaje alfabético, como Inglés o ruso, pero en absoluto suficiente para japonés o chino. Y ahora tenemos Unicode con sus puntos de código de 21 bits. Pero char no se pudo expandir a 16 o 32 bits porque la suposición de que char = byte estaba tan arraigada. Así que tenemos un tipo diferente para "personajes anchos".

Pero ahora tenemos el problema de que wchar_t es UTF-32 en Linux pero UTF-16 en Windows. Y para resolver que problema de la próxima versión del estándar C++ añadirá los char16_t y char32_t tipos (y tipos de cadenas correspondientes).