Contenedores de STL

download Contenedores de STL

of 31

description

Contenedores de STL

Transcript of Contenedores de STL

  • Contenedores de STL

    Javi Agenjo 2010Universitat Pompeu Fabra

  • Standard Template LibraryLa Standard Template Library es una librera estandar que contiene todo tipo de contenedores pensados para trabajar en C++. Al ser estndar viene en todos los compiladores de C. Es multiplataforma y est optimizada para que funcionen de la manera ms eficiente. Adems usan un interfaz comn que facilita el trabajo con diferentes tipos de contenedores.

    Dentro de STL podemos encontrar vectores, listas, pilas, conjuntos, tabla de hash y otros muchos tipos de contenedores, adems de algoritmos para trabajar con ellos.

  • Por qu es importante usar STL

    STL ha sido testeada durante dcadas por infinidad de programadores por lo que es muy segura y fiable.

    Ademas las diferentes implementaciones de STL estan pensadas para sacar el mximo partido al hardware.

    Evitan cometer fallos que puedan producir agujeros en la memoria ya que toda la gestin de la memoria del contenedor es automtica.

    Al ser templates casi todo se resuelve en tiempo de compilacin, por lo que es ms rpida que otros tipos de contenedores.

  • Qu es un contenedor?Un contenedor es un elemento de cdigo que nos permite almacenar y recuperar un conjunto de datos de manera cmoda y eficiente.

    Existen diferentes contenedores en funcin de cmo queremos que se gestione su almacenamiento en memoria.

    No existe un contenedor mejor que otro, solo uno ms adecuado para cada caso, por eso es importante conocer las particularidades de cada contenedor para saber cual emplear en cada situacin.

    STL no tiene restricciones sobre el tipo de datos que podemos guardar en un contenedor, ya que se basa en templates.

  • Templates

  • Qu son los templates?Los templates nos permiten crear clases en las que algun tipo de datos no est especificado en la definicin de la clase, dejando la libertad al programador de instanciar esta clase con un tipo especifico ms adelante.

    A ese tipo se le da un nombre genrico (por ejemplo. T). Cuando el programador instancia una clase que viene de un template le debe indicar el tipo de datos que quiere usar, y el compilador reemplaza en el template el tipo genrico por el tipo que le indica y acto seguido compila la clase.

    Los templates usan la sintaxis para indicar el parametro:

    //aqu creamos un vector de enterosstd::vector vector_de_enteros;

  • Qu son los templates?Un ejemplo de template y el resultado generado al expandir el template en tiempo de compilacin:

    Defino un template: template class MyClass{ T data; void setData(T v); };

    Si pongo MyClass m en algun lugar el compilador compilar: class MyClass{ float data; void setData(float v); };

    Usar templates hace el cdigo ms genrico pero puede dar pie a errores ya que no sabemos qu tipo se le pasar a una clase al definir el template.

  • Por qu usa templates la libreria STL?Porque de esta manera cualquier contenedor de STL puede almacenar cualquier tipo de datos que queramos, incluso clases creadas por nosotros. Sin embargo hay que tener presente una cosa, algunos contenedores requieren que el tipo de datos que le pasemos tenga definidos algunos operadores, como el de igualdad (A==B) o en el caso de los maps, el de "mayor qu" (A > B). Si el tipo que le pasamos tiene algn error o no tiene los operadores necesarios para ese contenedor, al expandirse el template se generar un error de compilacin y el compilador nos indicar el error en una lnea del template de STL lo cual puede resultar confuso para el programador.

  • Iteradores

  • Qu es un iterador?Un iterador es una estructura pensada para apuntar a un elemento de un contenedor.

    Tiene ciertas ventajas, la principal es que homogenizan el acceso a un contenedor sin importar de qu clase es el contenedor.

    Tambin permiten saltar de un elemento al siguiente o al anterior, o saber si hemos llegado al final de un contenedor. Los iteradores son muy importantes ya que estan muy optimizados y para ciertos contenedores son la nica manera que tenemos de poder recorrer todos sus elementos.

    Adems muchas de las funciones de STL requieren como parmetros de entrada iteradores, por ejemplo si queremos ordenar un rango de elementos de un contenedor necesitamos especificar el primero y el ltimo mediante iteradores.

  • Iteradores

    Los iteradores se declaran teniendo en cuenta el tipo de contenedor: std::list::iterator it; ya que tiene que coincidir con el tipo de datos.

    Si queremos acceder al elemento que apunta un iterador usamos el operador asterisco:

    (*it)->doSomething();

    Algunos iteradores pueden tener dos valores (key y datos), en tal caso usamos el operador flash: it->first y it->second

  • Iteradores: begin y endTodo contenedor tiene dos mtodos que es importante tener en cuenta a la hora de iterar:

    begin() retorna un iterador al primer elemento del contenedor, si el contenedor est vacio retorna lo mismo que end()

    end() retorna un iterador a la posicin despus del ltimo elemento del contenedor, no al ltimo elemento. Esto se hace para poder detectar si hemos llegado al final del contenedor cuando estamos iterando.

    Es importante notar que si tratamos de leer el elemento al que apunta end() la aplicacin fallar. Podemos comparar iteradores para saber si apuntan al mismo lugar.

  • Iteradores, trucos Si necesitamos iterar al revs (de atrs a adelante) usamos

    r_begin() y r_end()

    Atencin: No se deben modificar los contenedores mientras se itera por ellos, esto podra invalidar el iterador, y producir un error.

    Si nos da pereza escribir el tipo del iterador:

    std::map::iterator it = container.begin();

    C++ 99 (la ltima versin de C++) permite usar la palabra auto, entonces el compilador deduce el tipo mediante la asignacin:

    auto it = container.begin();

    Pero no todos los compiladores lo soportan.

  • Interfaz comnTodos los contenedores de STL usan un interfaz comn, esto significa que la manera de acceder a ellos es similar.

    Por ejemplo, para saber el nmero de elementos hacemos mycontainer.size() sin importar si es una lista o un vector. Si queremos vaciarlo podemos usar mycontainer.clear()

    Adems tienen los operadores de copia ya definidos por lo que podemos copiar un contenedor a otro fcilmente:

    //esto copia todos los valores de un contenedor al otro my_container = my_old_container;

  • Encontrar elementosA veces necesitamos saber si un elemento est dentro de un contenedor o la posicin que ocupa, para eso usamos el mtodo find. Este mtodo nos retorna un iterador al elemento, si el elemento no est retorna un iterador apuntando a end()

    Hay que tener en cuenta que el coste computacional del find depender del tipo de contenedor.

    std::list::iterator it = my_container.find( value );

    if ( it != my_container.end() ) std::cout

  • Borrar elementosPara borrar un elemento necesitamos tener un iterador al elemento que queremos borrar, para ello podemos utilizar mtodos como find o iterar hasta llegar al elemento que queremos.

    my_container.remove( it );

    Si borramos un elemento de un contenedor el iterador queda invalidado, es importante tenerlo en cuenta o podemos colgar la aplicacin.

    No podemos hacer remove(it) y luego it++

    Hay que recordar que el borrado de elementos en ciertos tipos de contenedores es poco eficiente, por ejemplo en un vector ya que requiere reposicionar todos los elementos que le siguen.

  • Tipos de contenedores

  • Tipos bsicos de STL

    Contenedores

    std::vector std::string std::liststd::set std::map

    Iteradores iterator reverse_iterator

  • Vectores (std::vector)Un vector es similar a un array, solo que gestiona automaticamente la memoria (reserva el espacio necesario, hace copias, etc)Nos permite almacenar secuencialmente en memoria una serie de datos.

    Ventajas permite hacer accesos aleatorios instantaneos. permite iterar rapidamente por los elementos. no requiere iteradores para acceder a los elementos.

    Inconvenientes Insertar elementos o borrar elementos es lento, ya que implica reorganizar

    el resto de datos. Si el tamao del vector se incrementa esto implica reservar toda la memoria

    de nuevo y hacer una copia de la anterior a la nueva posicin, por lo que no es ideal en casos donde no sabemos cuantos elementos tendremos.

    Hacer busquedas dentro del contenedor tiene un coste computacional elevado ya que implica recorrerselos todos hasta dar con l.

  • Vectores: sintaxis#include //creamos un vector de enteros std::vector< int > my_vector;

    //cambia el tamao del contenedormy_vector.resize(10); //iteramos por todos los elementos for (int i = 0; i < my_vector.size(); i++) my_vector[ i ] = rand() % 50; //asignamos un valor aleatorio

    //aadir al final un elemento nuevomy_vector.push_back( 100 );

  • Cadenas de texto (std::string)Tcnicamente se comporta como un vector de chars pero con funcionalidades aadidas para gestionar las cadenas. Permite almacenar de manera segura una cadena de texto y aplicar ciertas transformaciones. Ahorra tener que lidiar con problemas relacionados con la memoria (strings demasiado largos que se salen de rango, etc).

    Ventajas Gestiona la memoria de manera automtica, evitando la

    mayor parte de los errores de memoria habituales.

    Inconvenientes En comparacin con los arrays de chars tiene un ligero

    overhead.

  • String#include

    std::string my_text = "hola soy yo";

    my_text.size(); //indica el numero de caracteresmy_text[0]; //retorna el primer caractermy_text.substring(5,3); //retorna el string "soy"

    std::string my_new_text = my_text; //copia

    podemos retornar facilmente strings sin preocuparnos de quien es el propietario de la memoria ya que la clase hace copias automaticamente de las cadenas.

    Si necesitamos el puntero a const char* podemos obtenerlo:const char* txt = my_text.c_str();

  • Listas (std::list)Es una lista donde cada elemento est enlazado con el siguiente formando una cadena. Sirve para almacenar datos secuencialmente, similar a un vector pero con ligeras diferencias. Ventajas Insertar y eliminar valores tiene un coste fijo. Agregar ms valores no supone ningun coste extra No necesitamos saber cuantos valores habr.

    Inconvenientes No permite accesos aleatorios, tenemos que recorrernos la lista

    usando iteradores si queremos ir a una posicion. Fragmenta la memoria ya que cada valor se almacena en una

    direccin diferente. Encontrar un elemento tiene un coste computacional elevado.

  • Listas: Sintaxis#include std::list my_list;

    //insertamos dos elementosmy_list.push_back(5);my_list.push_back(15); //iteramosfor (std::list::iterator it = my_list.begin(); it != my_list.end(); it++){ //accedemos al elemento usando el iterador std::cout

  • Conjunto (std::set)Sirve cuando queremos almacenar un conjunto de datos pero no nos importa el orden, se comporta como una hash table donde la key es el propio valor.

    Ventajas Encontrar un elemento tiene un coste bajo. Ordena los valores automaticamente.

    Inconvenientes Iterar secuencialmente los valores tiene un coste elevado. Es obligatorio que el tipo de datos almacenado permita

    hacer comparaciones entre los datos (necesario para el sistema de almacenamiento basado en ordenacin).

  • Set (sintaxis)#include

    std::set my_tags;

    my_tags.insert("cold");my_tags.insert("white");my_tags.insert("water"); my_tags.insert("cold"); //repetimos uno

    std::set::iterator it; //iterador

    for (it=my_tags.begin();it != my_tags.end(); it++) std::cout

  • Contenedores key=>value (std::map)Similar al set, permite almacenar un conjunto de datos pero usando una clave (key) para cada uno.

    No es exactamente una tabla de hash ya que utiliza rboles balanceados para almacenar los datos.

    Ventajas Permite hacer bsquedas muy rpidamente Los costes de insercin/borrado no son elevados.

    Inconvenientes Iterar es muy lento. Memoria fragmentada. No pueden haber dos elementos con la misma clave.

  • Map (sintaxis)

    #include

    std::map my_scores;

    //puedes insertar usando el operador []my_scores["javi"] = 100;my_scores["juan"] = 50;

    //busca un elemento con la key "javi"std::map::iterator it;it = my_scores.find("javi");

    //si el elemento est imprime su valorif (it != my_scores.end() ) std::cout

  • MapVarias consideraciones sobre el map: Podemos insertar usando el operador corchete (mymap

    ["test"] = 10), pero no debemos usar ese operador para ver si existe un valor ya que dicho operador estar creando el elemento, hay que usar el metodo find.

    Si queremos usar strings como key debemos especificar como tipo de datos de la key un std::string, no un char* o const char*, ya que si usamos const char* usar la direccin del puntero como key, no donde apunta.

    Si queremos usar como key una clase propia podemos hacerlo, pero esa clase debe tener definidos los operadores de igualdad y comparacin.

  • Algoritmos y transformacionesExisten ademas funciones especiales pensadas para aplicar acciones a los elementos de un contenedor. Por ejemplo ordenar los valores (util para listas o vectores), aplicar una funcin a cada valor, encontrar el mximo o el mnimo de un contenedor, etc.

    Para ello definimos el callback necesario y se lo pasamos a la funcin que aplica la accin.

    Mirad la referencia del archivo

    http://www.cplusplus.com/reference/algorithm/

  • Conclusiones STL nos ahorra mucho trabajo de desarrollo. Es eficiente, se basan en templates para acelerar la

    ejecucin. Es multiplataforma Permite detectar errores que de otro modo seran poco

    visibles. Casi todos los usos que podamos pensar estan ya

    implementados.