Skip to content

[Boost en español I] Las bibliotecas en el TR1 (1ª part, Array y Hash)

3 julio 2010

Este es el primero de una serie de posts sobre Boost en español, en el que haremos un repaso por un subconjunto de estas bibliotecas.

Descargando, compilando y usando Boost

Además de su utilidad, las bibliotecas Boost brillan en su facilidad de uso, ya que la inmensa mayoría de las mismas están totalmente definidas en ficheros de cabecera que simplemente incluiremos en nuestro proyecto, evitando tener que compilarlas y enlazarlas de forma independiente. Hay una serie de bibliotecas que, por su complejidad, necesitan ser compiladas y enlazadas, pero son casos en los que la compilación es indispensable y merece la pena por la funcionalidad que ofrecen.

Hoy en día la mayoría de las distribuciones de GNU/Linux alojan en sus repositorios paquetes con las bibliotecas Boost. Por regla general, se distribuye un paquete con la mayoría de las bibliotecas de cabecera, y por separado un paquete por cada biblioteca que necesita enlazado. En esta serie de artículos se indicará convenientemente cuándo es necesario realizar alguna clase de operación especial al compilar y enlazar.

C++ Technical Report 1

Como comenté en el post anterior, vamos a empezar comentando por encima las bibliotecas de Boost que aparecen en el C++ Technical Report 1. Pero primero, ¿qué es ese documento?

Tal y como explica la wikipedia, se trata de un documento que propone una serie de adiciones a la biblioteca estándar de C++. No es un estándar en sí mismo, sino una propuesta borrador, aunque con toda probabilidad gran parte o la totalidad del mismo formará parte de la siguiente versión de C++. Por lo tanto, es interesante echarle un vistazo para familiarizarse con lo que está por llegar.

En cuanto a Boost, 12 de sus bibliotecas han sido incluídas en el TR1, aquí las veremos todas por encima y algunas con más profundidad.

Nota Dado que las primeras librerías que vamos a ver está en el TR1, es posible usar directamente las implementaciones de los compiladores.

Por ejemplo, para boost.array, en lugar de usar la cabecera boost/array.hpp podemos usar tr1/array (sin extensión, típico de la std), y cambiar el namespace boost por el tr1. Sin modificar nada más, el código compilará usando la implementación de array de GCC.

Boost.Array

Documentación: http://www.boost.org/doc/libs/1_43_0/doc/html/array.html
Cabecera: boost/array.hpp

Se trata de un wrapper que adapta las arrays de tamaño fijo, típicas de C, para su uso como contenedor estándar, añadiendo una serie de métodos y tipos de datos tales como size y at, iteradores, etcétera. Las ventajas sobre los arrays clásicos son claras: métodos útiles para conocer el tamaño, métodos de acceso con control de límites, etcétera.

Hay muchas ocasiones en las que utilizamos std::vector incluso sabiendo que el tamaño no va a variar, simplemente por evitar utilizar arrays a pelo. En esos casos, boost::array es ideal, ya que comparte la mayoría de métodos de vector y, al no tener que lidiar con ampliaciones y reducciones dinámicas de memoria, es mucho más eficiente.

Por último, otra de las grandes ventajas de esta biblioteca es la posibilidad de inicializarse en línea como un agregado, lo que nos evita andar inicializando los elementos uno a uno.

#include <boost/array.hpp>

#include <iostream>
#include <string>

using namespace std;

int main(int argc, char *argv[])
{
    /*
      Ejemplo 1: Inicialización básica de un boost::array
    */
    boost::array<string, 3> primos = { {"Shurmano", "Shurprimo", "Shurperro"} };
    cout << primos[0] << endl
	 << primos[1] << endl
	 << primos[2] << endl;

    /*
      Ejemplo 2: Métodos típicos de los contenedores
     */

    // Tamaño
    cout << "Tamaño: " << primos.size() << endl;

    // Bound checking (comprobación de límites)
    try{
	cout << primos.at(4) << endl;
    }catch(std::out_of_range&){
	cout << "Fuera de rango" << endl;
    }

    // Iteradores
    cout << *primos.begin() << endl
	 << *(primos.end()-1) << endl;

    // Operadores
    boost::array<int, 4> yo = { {0, 1, 2, 3} };
    boost::array<int, 4> another = { {0, 1, 2, 5} };
    cout << ((yo == another)?"Iguales":"Diferentes") << endl;

    return 0;
}

En este enlace se explican las motivaciones y detalles detrás de boost.array.

Boost.Hash

Documentación.
Cabecera: boost/functional/hash.hpp

Un hash es una forma de identificar de forma unívoca a cualquier elemento. Se utiliza una función hash que, a partir de las propiedades de un objeto, genera un código único. Los hashes se suelen utilizar en contextos en los que es necesario identificar e indexar elementos, como en los contenedores. La ventaja que ofrece el indexar por hash en lugar de por otro tipo de clave es que la comparación de hashes es muy eficiente, por lo que los accesos se hacen más rápido.

Boost.Hash nos permite generar hashes para enteros, flotantes, punteros y cadenas de forma nativa, y además, provee soporte para la generación de hashes de tipos de datos definidos por el usuario y hashes combinados. La utilización de esta biblioteca es muy sencilla: simplemente creamos una instancia de la clase paramétrica boost::hash, que recibe como parámetro el tipo de dato a hashear. Seguidamente, cuando queramos generar un hash, utilizaremos el operador () del objeto creado.

boost::hash<std::string> string_hash;
    cout << "Hash de cadena: " 
	 << string_hash("Don't hash me, bro!") << endl;

Si tenemos un tipo de datos propio, por ejemplo una clase, y queremos calcular su hash, previamente tendremos que sobrecargar la función size_t hash_value(const T & t), siendo T nuestro tipo de datos. Dentro de esa función tendremos que implementar el algoritmo de hash para nuestra clase concreta.

Por regla general, a la hora de implementar el hash de un tipo propio, tenemos que fijarnos en qué propiedades tiene cada instancia de esa clase que la hace única. Si, por ejemplo, tenemos una clase código de barras con un atributo número que la identifica, el hash de la clase será el hash del código.

class codigoBarras{
  int numero;
public:
  // ...
  friend std::size_t hash_value(const codigoBarras & C){
    boost::hash<int> hasher; 
    return hasher(C.numero);
  }
};

Otro ejemplo: si tenemos una clase alumno con dos atributos nombre y apellido, el hash de esa clase será una combinación del hash del nombre y el hash del apellido.

class alumno{
  string nombre, apellido;

public:
  // ...
  friend std::size_t hash_value(const alumno & a){
    std::size_t valor = 0;
    boost::hash_combine(valor, a.nombre);
    boost::hash_combine(valor, b.nombre);
    return valor;
  }
};

Boost.hash se utiliza en la biblioteca Boost.unordered, que proporciona alternativas no ordenadas a los conjuntos (set) y mapas (map) de la STL, mejorando la eficacia en órdenes de magnitud.

Hasta aquí la primera entrega de estos artículos.

About these ads
No comments yet

Deja un comentario

Introduce tus datos o haz clic en un icono para iniciar sesión:

Logo de WordPress.com

Estás comentando usando tu cuenta de WordPress.com. Cerrar sesión / Cambiar )

Imagen de Twitter

Estás comentando usando tu cuenta de Twitter. Cerrar sesión / Cambiar )

Foto de Facebook

Estás comentando usando tu cuenta de Facebook. Cerrar sesión / Cambiar )

Google+ photo

Estás comentando usando tu cuenta de Google+. Cerrar sesión / Cambiar )

Conectando a %s

Seguir

Recibe cada nueva publicación en tu buzón de correo electrónico.

%d personas les gusta esto: