Repaso a la STL: Introducción a los contenedores

Repaso a la STL: Introducción a los contenedores
Sin comentarios Facebook Twitter Flipboard E-mail

Vamos a dedicar una serie de artículos a hablar de la Biblioteca de plantillas estándar (STL) de C++. Esta poderosa herramienta usada por casi todo los programadores de C++ de la que hay muy poca documentación disponible en nuestro idioma.

La STL es una colección de estructuras de datos y algoritmos de uso común. Está basada en plantillas utilizando programación genérica. Está diseñada para ser eficiente, evita el uso de funciones virtuales en favor de las plantillas evitando operaciones en tiempo de ejecución.

La STL se podría dividir en tres grandes partes: Contenedores (plantillas de estructuras de datos populares), iteradores y algoritmos.

Introducción a los contenedores

Los contenedores de la STL son estructuras de datos capaces de contener casi cualquier tipo de objeto (hay algunas restricciones). Existen 3 tipos de clases contenedoras: contenedores de primera clase, adaptadores y casi-contenedores.

También podemos catalogar a los contenedores por el tipo. Existen 3 tipos de contenedores: Contenedores de secuencia, Contenedores asociativos y Adaptadores de contenedores. Vamos a ver una tabla con los tipos de contenedores que hay.

Clase Contenedora Descripción
Contenedores de secuencia (primera clase)
vector Inserción y eliminación rápida en la parte final. Acceso directo a cualquier elemento.
deque Incersiones y eliminaciones rápidas en la parte inicial o final. Acceso aleatorio a cualquier elemento.
list Lista con enlace doble, incersión y eliminación rápida en cualquier parte.
Contenedores asociativos (primera clase)
set Búsqueda rápida, no se permiten duplicados.
multiset Búsqueda rápida, se permiten duplicados
map Asociasión de uno a uno, no se permiten duplicados, búsqueda rápida basada en claves.
multimap Asociasión de uno a uno, se permiten duplicados, búsqueda rápida basada en claves.
Adaptadores de contenedores
stack Último en entrar primero en salir (UEPS).
queue Primero en entrar, primero en salir (PEPS).
priority_queue El elemento de mayor prioridad siempre es el primero en salir.

Las contenedores de secuencia representan estructuras de datos lineales tales come vectores y listas enlazadas. Los contenedores asociativos representan estructuras de datos no lineales que por lo general pueden localizar elementos almacenados en ellos rápidamente. Dichos elementos pueden almacenar conjuntos de valores, o pares clave/valor. Los contenedores de secuencia y los contenedores asociativos son los contenedores de primera clase. Las pilas (stack), las colas (queue) y las colas priorizadas (priority queue) son en realidad versiones restringidas de los contenedores de secuencia. Por esta razón la STL los implementa como adaptadores de contenedores que permiten a un programa ver un contenedor de secuencia de manera restringida.

Existen otro tipo de contenedores los conocidos como casi-contenedores que son los arreglos basados en punteros tipo C, los contenedores bitset para mantener conjuntos de valores de bandera y contenedores valarray para llevar a cabo operaciones vectoriales matemáticas de alta velocidad (esta última clase esta optimizada para un buen rendimiento del compilador y no es tan flexible como los contenedores de primera clase). Se les consideran casi-contenedores porque guardan similitud con los contenedores, pero no soportan todas sus capacidades. El tipo string de la STL, por ejemplo, soporta la misma funcionalidad que un contenedor de secuencia, pero sólo almacena datos de tipo carácter.

Funciones comunes de los contenedores

La mayoría de contenedores de la STL proporcionan una funcionalidad similar. Hay muchas operaciones genéricas, como el método size, que se aplica a todos los contenedores. La siguiente tabla muestra los métodos comunes en todos los contenedores.

Los operadores sobrecargados operator<, operator<=, operator>, operator>=, operator== y operator!= no se proporcionan para contenedores priority_queue.

Funciones miembros comunes Descripción
constructor predeterminado Un constructor para crear un contenedor vacío. Por lo general, cada contenedor cuenta con varios constructores que proporcionan distintos métodos de inicialización.
constructor de copia Un constructor que inicializa al contenedor para que sea una copia de un contenedor existente del mismo tipo.
destructor La función destructora para encargarse de la limpieza, una vez que el contenedor ya no sea necesario.
empty Devuelve true si no hay elementos en el contenedor, en caso contrario devuelve false.
insert Inserta un elemento en el contenedor.
size Devuelve el número de elementos que hay actualmente en el contenedor.
operator= Asigna un contenedor a otro.
operator< Devuelve true si el primer contenedor es menor que el segundo, en caso contrario devuelve false.
operator<= Devuelve true si el primer contenedor es menor o igual que el segundo, en caso contrario devuelve false.
operator> Devuelve true si el primer contenedor es mayor que el segundo, en caso contrario devuelve false.
operator>= Devuelve true si el primer contenedor es mayor o igual que el segundo, en caso contrario devuelve false.
operator== Devuelve true si el primer contenedor es igual que el segundo, en caso contrario devuelve false.
operator!= Devuelve true si el primer contenedor es distinto que el segundo, en caso contrario devuelve false.
swap Intercambia los elementos de dos contenedores.
Funciones que solo se enecuentran en contenedores de primera clase
max_size Devuelve el número máximo de elementos para un contenedor.
begin Las dos versiones de esta función devuelven ya sea un iterator o un const_iterator que hace referencia al primer elemento del contenedor.
end Las dos versiones de esta función devuelven ya sea un iterator o un const_iterator que hace referencia a la siguiente posición después del final del contenedor.
rbegin Las dos versiones de esta función devuelven ya sea un reverse_iterator o un const_revese_iterator que hace referencia al último elemento del contenedor.
rend Las dos versiones de esta función devuelven ya sea un reverse_iterator o un const_revese_iterator que hace referencia a la posición que está antes del primer elemento del contenedor.
erase Elimina uno o más elementos del contenedor.
clear Elimina todos los elementos del contenedor.

Archivos de encabezado de la STL

En la siguiente tabla se muestran los archivos de encabezado necesarios para los distintos contenedores. Todo el contenido de estos archivos de encabezado está dentro del namespace std

Archivos de encabezado de la STL
<vector>
<list>
<deque>
<queue> Contiene tanto a queue como a priority_queue.
<stack>
<map> Contiene tanto a map como a multimap.
<set> Contiene tanto a set como a multiset
<valarray>
<bitset>

Definiciones typedef comunes de los contenedores de primera clase

En la siguiente tabla se muestran los elementos typedef (para crear sinónimos o alias de tipos extensos) comunes que se encuentran en los contenedores de primera clase. Estos elementos typedef se utilizan en declaraciones genéricas de variables, parámetros a funciones y valores de retorno de las funciones. Por ejemplo, value_type en contenedor es siempre un typedef que representa el tipo de valor almacenado en el contenedor.

typedef Descripción
allocator_type El tipo de objeto utilizado para aasignar la memoria del contenedor.
value_type El tipo de elemento almacenado en el contenedor.
reference Una referencia al tipo de elemento almacenado en el contenedor.
const_reference Una referencia constante al tipo de elemento almacenado en el contenedor. Dicha referencia sólo puede ser utilizada para leer elementos y colocarlos en el contenedor, y para realizar operaciones const.
pointer Un puntero al tipo de elemento almacenado en el contenedor.
const_pointer Un puntero al tipo de elemento constante almacenado en el contenedor.
iterator Un iterador que apunta al tipo de elemento almacenado en el contenedor.
const_iterator Un iterador constante que apunta al tipo de elemento almacenado en el contenedor y que solo puede utilizarse para leer elementos.
reverse_iterator Un iterador inverso que apunta al tipo de elemento almacenado en el contenedor. Este tipo de iterador es para iterar a través de un contenedor en sentido inverso.
const_reverse_iterator Un iterador inverso constante que apunta al tipo de elemento almacenado en el contenedor y que solo puede utilizarse para leer elementos. Esti tipo de iterador es para iterar a través del contenedor en sentido inverso.
difference_type El tipo del resultado obtenido al restar dos iteradores que hacen referencia al mismo contenedor (operator- no está definido para iteradores de contenedores list ni contenedores asociativos).
size_type El tipo utilizado para contar elementos en un contenedor e indizar a través de un contenedor de secuencia (no se puede indizar a través de un contenedor list).

Al utilizar contenedores de la STL, es importante asegurar que el tipo de elemento que vaya a almacenarse en el contenedor soporte un conjunto mínimo de funcionalidad. Al insertar un elemento en un contenedor, se crea una copia de ese elemento. Por esta razón el tipo de elemento debe proporcionar su propio constructor copia y operador de asignación (esto solo se requiere si la copia y la asignación predeterminada a nivel de miembro no se realizan operaciones apropiadas de copia y asignación para el tipo de elemento). Además, los contenedores asociativos y muchos algoritmos requieren de la comparación de elementos. Por esta razón, el tipo del elemento debe proporcionar un operador de igualdad == y un operador menor que <.

Técnicamente, los contenedores de la STL no requieren comparar sus elementos con los operadores de igualdad y menor que, a menos que un programa utilice una método del contenedor que deba comparar elementos (por ejemplo, la función sort en la clase list). Por desgracia, algunos compiladores de C++ previos al estándar no son capaces de ignorar la parte de la plantilla que no se utiliza en un programa específico. En los compiladores con este problema, tal vez deba sobrecargar los operadores == y < de los objetos que vayas a insertar en un contenedor de la STL.

Hemos visto una introducción a los contenedores los tipos que hay las funciones miembros comunes a ellos, sus archivos de encabezado y los typedef comunes. En el siguiente artículo haremos una introducción a los iteradores y en los sucesivos empezaremos a ver específicamente cada contenedor y usarlos en la práctica.

Comentarios cerrados
Inicio