EVAP2

Habida cuenta que la misión principal de los contenedores es el almacenamiento de objetos, resulta natural que entre sus funciones más importantes, se encuentre la gestión del espacio necesario para albergarlos. Esta gestión no se limita a asignar y liberar el espacio necesario para sus miembros. En ocasiones también debe gestionar espacio para la estructura de índices que mantiene el orden de la secuencia. Por ejemplo, cuando añadimos miembros a un contenedor tipo vector, este se redimensiona automáticamente conforme se van añadiendo nuevos elementos.  Análogamente, cuando añadimos nuevos elementos a un map este acomodo afecta a los nuevos elementos y a las claves asociadas que constituyen su sistema de índice.
Como se ha dicho, todas las entidades de la STL que precisan de memoria dinámica lo hacen a través de los "servicios" de una clase "asignadora" que es utilizada como argumento (recuerde que las entidades de la STL son plantillas que aceptan distintos parámetros). Debido a que además de portable, la STL es extensible, existe libertad para que el usuario implemente su propio asignador de memoria; aunque la STL proporciona un gestor por defecto, la clase allocator, que implementa la funcionalidad requerida mediante la utilización de los operadores estándar new y delete . En caso de no indicarse otro explícitamente, se utiliza este asignador por defecto, que suele ser suficiente en la mayoría de los casos. El resultado es que el usuario puede despreocuparse de la cuestión, y que los asignadores son ráramente utilizados de forma explícita. Por ejemplo, la definición del contenedor vector es del siguiente tenor:

espacio de nombres std {
          template <class T, asignador class = asignador <T>> clase
vector
    pública:
                                                                                                                                 ...
     };
}
Desde la perspectiva del usuario de un contenedor estándar, el manejo de memoria es realizado automáticamente mediante el parámetro de moldeo.  Por ejemplo, para definir una lista de enteros myList utilizando el asignador por defecto, puede utilizarse el parámetro <int> y escribir:

# Include <Memoria>
...
Lista <INT> mi lista;

En la declaración del contenedor también puede proporcionarse un asignador específico mediante un segundo parámetro de moldeo. Por ejemplo, para utilizar en la lista anterior un asignador propio denominado fastAllocator, que suponemos está pensado para tipos int, y definido en el fichero de cabecera <fastAllocator.h>, utilizaríamos la definición siguiente:

#include <memory>
#include <fastAllocator.h>
tipedef list <int, fastAllocator> myList

También podría utilizarse el asignador por defecto de forma explícita:

# include <memory>
allocator<int> miAllocint;
list <int, miallocint> mylist;

Como puede verse, cuando se instancia una especialización concreta de un contenedor genérico, debe especificarse el tipo de miembro que alojará en el contenedor y el asignador de memoria que utilizara. Posteriormente, cuando se instancie un objeto del tipo myList, se especifica el objeto-asignador que utilizará el contenedor:

fastAllocator asignadorl;
mylist listal (asignadorl);

 El manejador por defecto:

Las definiciones de los asignadores de la STL están en el espacio de nombres std y se encuentran agrupadas en la cabecera <memory>.  La STL proporciona un manejador por defecto denominado allocator.  Esta clase es en realidad una plantilla que puede instanciarse para manejar cualquier tipo. Responde a la siguiente interfaz:


Por supuesto que la clase satisface las premisas indicadas por el Estándar para ser un allocator por lo que es un asignador estándar. También se proporciona una instanciación para el tipo voidque responde a la siguiente interfaz:


Ejemplos


vector<double> V(100, 5.0);     // Usa el asignador por defecto
vector<double, single_client_alloc> local(V.begin(), V.end());

No hay comentarios:

Publicar un comentario