Tabla de contenido
-
-
- 1. Introducción a STL
- 2. Uso de clase de cadena
-
- 2.1 Cadenas en lenguaje C
- 2.2 La clase de cadena en la biblioteca estándar
- 2.3 Descripción de la interfaz común de la clase de cadena (explica solo la interfaz más utilizada)
-
- 2.3.1 Construcción común de objetos de clase de cadena
- 2.3.2 Operación de capacidad de objetos de cadena
- 2.3.3 Operación de modificación del objeto de clase de cadena
- 2.3.5 Iterador (adelante)
- 2.3.6 Iteradores inversos
- 2.3.7 iterador constante (adelante y atrás)
- 2.3.8 Acceso a elementos
- 2.3.9 `insertar` y `borrar`
- 2.3.10 reemplazar, buscar, rfind, substr
- 2.3.11 cadena::intercambiar
- 2.3.12 cadena_c
- 2.3.13 obtener línea
- 2.4 Resumen
-
1. Introducción a STL
1.1 ¿Qué es STL?
STL (biblioteca de plantillas estándar libaray-plantilla estándar): es una parte importante de la biblioteca estándar de C ++, no solo una biblioteca de componentes reutilizable, sino también un marco de software que incluye estructuras de datos y algoritmos.。
Versión 1.2STL
- Copia original
La versión original completada por Alexander Stepanov y Meng Lee en Hewlett-Packard Labs, en el espíritu del código abierto, declaran que permiten a cualquier persona usar, copiar, modificar, difundir y utilizar comercialmente estos códigos libremente sin pago. La única condición es que también debe utilizarse como código abierto como la versión original.
Versión HP: el abuelo de todas las implementaciones STL。
- versión pijama
Desarrollado por PJ Plauger, heredado de la versión HP, adoptado por Windows Visual C++, no se puede divulgar ni modificar, defecto: baja legibilidad, denominación de símbolos extraña.
- versión RW
Desarrollado por Rouge Wage Company, heredado de la versión HP, adoptado por C++ Builder, no se puede divulgar ni modificar y su legibilidad es media.
- versión SGI
Desarrollado por Silicon Graphics Computer Systems, Inc., heredado de la versión HP. Adoptado por GCC (Linux), tiene buena portabilidad, se puede hacer público, modificar e incluso vender, y desde el punto de vista del estilo de nomenclatura y estilo de programación, es muy legible.Cuando aprendamos STL más adelante, necesitaremos leer parte del código fuente, la referencia principal es esta versión.。
1.3 Seis componentes principales de STL
Comprenda los seis componentes principales primero y aprenda lentamente después.
1.4 Defectos de STL
- La actualización de la biblioteca STL es demasiado lenta. Esta es una queja seria: la versión anterior era C ++ 98 y el C ++ 03 intermedio fue básicamente revisado. Han pasado 13 años desde que salió C++ 11 y STL solo se actualizó más.
- Actualmente, STL no admite la seguridad de subprocesos. En un entorno concurrente, necesitamos encerrarnos. Y la granularidad de la cerradura es relativamente grande.
- La búsqueda extrema de eficiencia por parte de STL conduce a la complejidad interna. Como extracción de tipos, extracción de iteradores.
- El uso de STL tiene el problema de la expansión del código. Por ejemplo, el uso de vector/vector/vector generará múltiples copias de código. Por supuesto, esto se debe a la sintaxis de la plantilla en sí.
2. Uso de clase de cadena
2.1 Cadenas en lenguaje C
En lenguaje C, una cadena es una colección de algunos caracteres que terminan en '\0'. Para facilitar la operación, la biblioteca estándar de C proporciona algunas funciones de biblioteca de la serie str, pero estas funciones de biblioteca están separadas de la cadena y no Se ajusta a la idea de programación orientada a objetos (idea orientada a objetos), y el espacio subyacente debe ser administrado por el usuario, y se puede acceder a él fuera de los límites si no se tiene cuidado.
2.2 La clase de cadena en la biblioteca estándar
La clase de cadena es en realidad una clase de plantilla instanciada a partir de una plantilla de clase.
Introducción a la documentación de la clase de cadena.
Podemos ver que en realidad esbasic_string
una definición de tipo de la clase instanciada a partir de esta plantilla de clase.
Aquí,
basic_string
además de la cadena, se crean instancias de otras tres clases de plantilla.
Todas son clases de plantilla instanciadas a partir de la plantilla de clase basic_string, la diferencia es que los tipos de sus parámetros de plantilla correspondientes son diferentes.。
Para la clase de cadena: de hecho, su capa inferior es una matriz de caracteres dinámica,
cadena es unchar
tipo de matriz de caracteres wstring es la matriz de caracteres
correspondiente u16string es la matriz de caracteres u32string es la matriz de caracteres Los tamaños correspondientes de estos diferentes tipos de caracteres son también diferente.wchar_t
char16_t
char32_t
Entonces, ¿por qué inventar tantos personajes?
En realidad, esto se debe a que
todos los símbolos y letras del código ASCII tienen un valor de código ASCII correspondiente.
De hecho, las letras en sí no se almacenan en la memoria, sino sus valores de código ASCII correspondientes (que se muestran aquí en hexadecimal).
Pero ASCII se usa principalmente para mostrar idiomas como el inglés, y hay muchos países e idiomas en el mundo. Por ejemplo, si queremos que las computadoras muestren chino, el código ASCII no funcionará.
Por esta razón, alguien inventó Unicode-Unicode (compatible con ASCII):
Unicode se divide en ,UTF-8
yUTF-16
estosUTF-32
.
Entonces, para manejar estas diferentes codificaciones, se producen estos diferentes tipos de caracteres, por lo que existe
basic_string
esta plantilla de clase de cadena genérica, que podemos usar para crear instancias de diferentes tipos de clases de cadena.
Resumir:
- cadena es una clase de cadena que representa cadenas
- La interfaz de esta clase es básicamente la misma que la de los contenedores normales, y se agregan algunas operaciones regulares especialmente utilizadas para manipular cadenas.
- la cadena está en realidad en la parte inferior:
basic_string
el alias de la clase de plantilla,typedef basic_string<char, char_traits, allocator> string;
- No se pueden manipular secuencias de caracteres multibyte o de longitud variable.
- Cuando utilice la clase de cadena, debe incluir archivos de encabezado #include y usar el espacio de nombres std;
2.3 Descripción de la interfaz común de la clase de cadena (explica solo la interfaz más utilizada)
2.3.1 Construcción común de objetos de clase de cadena
(constructor) nombre de la función | Función descriptiva |
---|---|
string() (enfoque del constructor predeterminado del constructor de cadena vacía) | Construye una cadena vacía con caracteres de longitud cero |
cadena (const char* s) (énfasis) | Construye un objeto similar a una cadena a partir de una cadena constante |
cadena (const string& str, size_t pos, size_t len = npos) (no se usa con frecuencia) | Copia la parte de str que comienza en la posición del carácter pos y abarca len caracteres (o hasta el final de str si str es demasiado corto o len es string::npos) |
cadena (const char* s, size_t n) | Tome s para apuntar a los primeros n caracteres de la cadena para construir un objeto de cadena |
cadena (size_t n, char c) | Tome n caracteres c para construir un objeto de cadena |
cadena (cadena constante y cadena) (énfasis) | copiar construcción |
cadena de plantilla (InputIterator primero, InputIterator último) | Después del iterador |
Empecemos a explicar uno por uno:
string()
Aquí construimos una cadena vacía.
- **
string (const char* s)
**
Esto también se admite aquí:
esto es de lo que hablamos antesEl constructor de un solo parámetro admite la conversión de tipos implícita。
string (const string& str, size_t pos, size_t len = npos)
Aquí, se utiliza una subcadena en str para construir un objeto de cadena. Esta cadena comienza desde la posición pos del subíndice en str y tiene una longitud de len.
Si el de aquístr
es más corto, o si se proporciona aquílen
,string::npos
entonces esta cadena va alstr
final de.
Para dar un ejemplo simple:
La longitud aquí es 30, por lo que la longitud de la cadena aquí no es suficiente, es más corta que 30, pero no se informará ningún error aquí y la posición final de la cadena se tomará aquí.. Si se
proporciona aquí , irá al final de str y el valor predeterminado se proporcionará aquí, que es el valor predeterminado . ¿ Qué hay aquí ?len
string::npos
len
npos
npos
Es una variable miembro estática con un valor de -1, pero aquí su tipo essize_t
(entero sin signo), por lo que en realidad es el valor máximo del entero aquí.。
string (const char* s, size_t n)
Utilice s para señalar los primeros n caracteres de la cadena para construir un objeto de cadena:
string (size_t n, char c)
Utilice n caracteres c para construir un objeto de cadena
string (const string& str)
Copiar construcción:
2.3.2 Operación de capacidad de objetos de cadena
size
ylengh
ambos devuelven la longitud de la cadena.
Aquí quizás se pregunte por qué es necesario escribir dos interfaces para la misma función.
De hecho, tiene algo que ver con algunas razones históricas.La cadena apareció antes que STL, estrictamente hablando, la cadena no pertenece a STL, es generada por la biblioteca estándar de C++ y existía antes de que apareciera STL..
La cadena se diseñó originalmente como longitud, pero después de la aparición de STL, otras estructuras de datos en ella usaban tamaño, por lo que para mantener la coherencia, se agregó un tamaño a la cadena.
por lo tantoEl principio de implementación subyacente de los métodos size() y length() es exactamente el mismo. La razón para introducir size() es ser consistente con las interfaces de otros contenedores. En general, size() se usa básicamente。
max_size
Lo que hace es devolver la longitud máxima que puede tener la cadena.
De hecho, la cadena no puede ser tan larga y el valor es diferente en diferentes plataformas.。
capacity
Aquí se devuelve la capacidad del objeto de cadena actual (es decir, cuánto espacio se le asigna actualmente, expresado en bytes)
==Aquí no incluye el espacio para '\0', porque cree que '\0' no es un carácter válido.。
Para otros veteranos, pueden verlo temporalmente junto con el documento y se lo explicaré más adelante.
2.3.3 Operación de modificación del objeto de clase de cadena
push_back
Como su nombre lo indica, significapush_back
inserción de cola ( añadir 1 carácter ).
append
Si desea agregar una cadena, puede usarappend
Hay muchas versiones sobrecargadas aquí, pero la más utilizada es agregar directamente una cadena
operator+=
De hecho, normalmente no nos gusta usarpush_back
yappend
. En lugar de eso, úsalooperator+=
.
La cadena está sobrecargada+=
(como se menciona en el artículo antes de la sobrecarga del operador), lo cual es muy conveniente de usar.
2.3.4 resize
yreserve
resize
Con el conocimiento anterior, volvamos a mirar la suma en la capacidad reserve
.
Antes de eso, observemos cómo un objeto de cadena se expande en el proceso de inserción continua de datos.
int main()
{
string s;
size_t sz = s.capacity();
cout << "capacity changed: " << sz << '\n';
for (int i = 0; i < 100; ++i)
{
s.push_back('c');
if (sz != s.capacity())
{
sz = s.capacity();
cout << "capacity changed: " << sz << '\n';
}
}
return 0;
}
Aquí, casi todas las expansiones del código VS son una expansión doble.
Después de comprender brevemente el mecanismo de expansión aquí, echemos un vistazo
reserve
.reserve
puede ayudarnos a cambiar la capacidad, de modo que si sabemos cuánto espacio necesitamos, podamos abrirlo en el lugar al mismo tiempo, para no tener que ampliar la capacidad una y otra vez..
Ahora especificamos la capacidad de reserva 100,No tiene que ser 100, tal vez por algunas razones como la alineación, te dará más espacio, pero definitivamente no será menor que 100.。
Si sabemos cuánto espacio necesitamos, reservar puede ayudarnos a abrir espacio con anticipación y luego reducir la expansión y mejorar la eficiencia.。
¿De qué sirve eso resize
?
resize
No solo se puede abrir el espacio, sino que también se puede inicializar el espacio abierto.
Aquí no especificamos el segundo parámetro, los caracteres a completar se proporcionan de forma predeterminada\0
, por supuesto, también podemos especificar los caracteres a completar nosotros mismos:
>
Si el n que pasamos es menor que la longitud de la cadena actual, También puede ayudarnos a eliminar el contenido adicional :
Tenga en cuenta que sólo cambia aquísize
,capacity
no.
En circunstancias normales, no es fácil reducir la capacidad. Si se reduce la capacidad, generalmente no admite la reducción in situ. Debido a algunas razones de la gestión de memoria subyacente, no se puede reducir in situ.
Si se admite la contracción en el lugar, ¿es necesario admitir la liberación de una parte? Solicitamos un espacio y solo se libera una parte si no se utiliza.
Pero no admite solo una parte de forma gratuita, ya que no es necesario que pasemos el puntero de forma gratuita, sino que debe apuntar a la ubicación real.
Entonces, si realmente desea reducir, solo puede reducir en un lugar diferente, es decir, abrir un nuevo espacio pequeño, copiar los datos requeridos allí y luego liberar el espacio original. Por lo tanto, la reducción de la capacidad se produce a costa del rendimiento, que no es compatible con el sistema de forma nativa y debemos hacerlo nosotros mismos. Así que no te encojas fácilmente a menos que sea necesario.
2.3.5 Iterador (adelante)
Ahora queremos iterar sobre un objeto de cadena. Primero, podemos usar
[ ]
transversal porque la cadena está sobrecargada[ ]
, o puedo usar rango para. Además de estos métodos, también podemos utilizar iteradores.
Tomemos un ejemplo sencillo:
int main()
{
string s1("hello world");
string::iterator it = s1.begin();
while (it != s1.end())
{
cout << *it << " ";
it++;
}
return 0;
}
El it aquí es un iterador de la clase de cadena que definimos (string::iterator
es un tipo). En esta etapa, puedes pensar en un iterador como algo así como un puntero (no necesariamente un puntero).。
El inicio aquí devolverá un iterador que apunta al primer carácter de la cadena.。
El final aquí devolverá un iterador que apunta a la posición después del último carácter..
Podemos entenderlo como un puntero a dos posiciones:
2.3.6 Iteradores inversos
Además de admitir el recorrido hacia adelante y hacia atrás como se indicó anteriormente, los iteradores también admiten el recorrido inverso, y el recorrido inverso se denomina iterador inverso.
Aquí rbegin() devuelve un iterador inverso que apunta al último carácter de la cadena..
aquírend() devuelve un iterador inverso que apunta al carácter anterior de la cadena。
Veamos nuevamente el ejemplo anterior:
int main()
{
string s1("hello world");
string::reverse_iterator it = s1.rbegin();
while (it != s1.rend())
{
cout << *it << " ";
it++;
}
return 0;
}
2.3.7 iterador constante (adelante y atrás)
Para objetos constantes que no se pueden modificar, los iteradores ordinarios pueden considerarlo como algo parecido a un puntero, luegoNo podemos modificarlo eliminando la referencia, por lo que no podemos usar iteradores ordinarios aquí, lo que provocará una amplificación de privilegios.。
Vemosbegin()
que si comienzan las llamadas a un objeto constante, se devuelve el iterador constante const_iterator. Los iteradores ordinarios pueden leer y modificar datos, pero los iteradores constantes solo se pueden leer y no se pueden modificar.。
El iterador inverso constante es el iterador que el objeto constante llama
rbegin()
yrend()
devuelveconst_reverse_iterator
Aquí C++ 11 proporciona otro conjunto de iteradorescbegin cend crbegin crend
, que solo devuelven iteradores constantes.
2.3.8 Acceso a elementos
La cadena está sobrecargada
[]
, podemos usarla directamente:
operator[]
También hay una versión normal y una versión constante. El objeto normal llama a [] y devuelvechar&
el objeto constanteconst char&
, que no se puede modificar.
at
El efecto[]
es el mismo. Sin embargo, todavía existe una diferencia entre los dos, la diferencia es:
Si[]
se accede fuera de los límites, informará directamente un error y utilizará aserciones para juzgar internamente.at
está lanzando una excepción
back
La función de yfront
es devolver el último y el primer carácter, pero podemos usar esto[]
para hacerlo, para que puedas entenderlo fácilmente.
2.3.9 insert
yerase
Al usarlo
insert
, podemos insertar caracteres y cadenas en el objeto de cadena:
aquí insert proporciona varias versiones, solo necesitamos dominar algunas de las más utilizadas.
Ahora queremos insertar una cadena hola delante del mundo, podemos considerar usar esto:
El primer parámetro es la posición a insertar, el segundo es la cadena insertada..
Ahora queremos insertar un espacio en la quinta posición, podemos usar esto:
También podemos considerar el uso de iteradores:
Aviso:Para cuerdas, no recomendamos el uso frecuente del inserto. Debido a que la capa inferior de la cadena es una matriz de caracteres, hemos aprendido la estructura de los datos y sabemos que para insertar elementos en la tabla de secuencia es necesario mover los datos, y la eficiencia es relativamente baja.。
Veámoslo de nuevo
erase
:
erase
Es eliminar los elementos en el objeto de cadena.
Para dar un ejemplo simple:
Ahora podemos aprovechar laerase
eliminación de espacios finales:
2.3.10 reemplazar, buscar, rfind, substr
Echemos un vistazo a reemplazar:
la función de reemplazar es en realidad reemplazar parte de la cadena con contenido nuevo. Aquí también elegimos explicaciones de uso común.
Tomemos un ejemplo:
Ahora necesitamos reemplazar los espacios en s con "hhh":
Veamos encontrar nuevamente:
find puede buscar una cadena o un carácter en una cadena y devolver el subíndice correspondiente. no encontrado devolver npos
Pongamos otro ejemplo:
ahora quiero encontrar "w" en s:
Veamos rfind nuevamente:
find es encontrar la primera coincidencia de adelante hacia atrás, rfind es encontrar la última coincidencia de atrás hacia adelante
Miremos substr nuevamente:
substr
puede ayudarnos a obtener una subcadena especificada en el objeto de cadena.
Por ejemplo:
aquí obtenemos la subcadena con una longitud de cinco a partir de la sexta posición.
2.3.11 cadena::intercambiar
A diferencia del intercambio en la biblioteca estándar, el intercambio aquí recibe un objeto de cadena y lo intercambia con el objeto actual.。
2.3.12 cadena_c
Echemos un vistazo nuevamente
c_str
:
su función es devolver un puntero a la matriz de caracteres correspondiente al objeto de cadena actual, y el tipo es const char*.
2.3.13 obtener línea
Tomemos un ejemplo:
int main()
{
string s;
cin >> s;
cout << s << endl;
return 0;
}
Ahora quiero ingresar hola mundo, ¿puede salir normalmente?
El cin aquí, cuando los usamos para ingresar, es posible ingresar múltiples valores, luego, cuando ingresamos múltiples valores, usan espacios o nuevas líneas de forma predeterminada para distinguir los múltiples valores que ingresamos.
Entonces, lo que ingresamos aquíhello world
se considerará como dos valores separados por un espacio, por lo que el valor cin se lee hola antes del espacio y el siguiente mundo se deja en el búfer.
Podemos
getline
solucionar este problema con:
getline finaliza cuando lee un espacio y, por supuesto, también nos permite especificar el terminador. El primer parámetro es recibir cin y el segundo parámetro es recibir el objeto de cadena que queremos ingresar.。
2.4 Resumen
Aquí se trata de la interfaz común de cadena. Hay muchas interfaces de cadena aquí. Si encuentra algo que no está claro más adelante, le sugiero que lea la cadena del documento oficial.