next up previous contents
Next: Resumen Up: 5.2 Implementación Previous: 5.2.1 Una primera implementación   Contents

5.2.2 Una implementación más robusta

La anterior implementación tiene el problema de que no verifica en ningún momento si la memoria se a agotado, el programa no es robusto.Esto es necesario, porque un programa no debe comenzar a funcionar aletoriamente, debe tener un comportamiento predecible ante los casos de excepción.

Par hacer más robusta nuestra implementación del TDA Arreglo vamos a incluir el concepto de excepción. Veamos el código:

/*

arregloExc.h

Autor: L. Alejandro Bernal R.

Fecha: 2000.12.02

Descripción: Implementa el concepto de un arreglo variable con exceptiones.

*/

#ifndef _ARREGLOEXC_H_

#define _ARREGLOEXC_H_

#include <stdlib.h>

#include <stdio.h>

/*

TDA Arreglo

    Descripción: Un arreglo es una secuencia de elementos de tamaño variable.

    Invariante: Arreglo=<elem[0],...,elem[n-1]> y (Para todo i,0 <= i<n,elem[i] pertenece a TipoB)

*/

template<class TipoB> class Arreglo

{

    private:

    // Atributos:

    TipoB *elem; // Arreglo de elementos.

    int num; // Número actual de elementos.

    public:

    // Excepciones:

    class NoHayMemoria { }; // Excepción: No hay memoria.

    class FueraRango { }; // Excepción: Fuera de rango.

    // Operaciones:

    /*

    Operación Arreglo 

        Descripción: Crea un arreglo vacio.

        Descripción operacional: Arreglo: -> Arreglo

        Precondición: verdadero 

        Poscondición: Arreglo=<>

    */

    Arreglo() { elem = NULL; num= 0; }

    /*

   Operación Arreglo

       Descripción: Crea un arreglo basado en un arreglo fuente.

       Descripción operacional: Arreglo: Arreglo -> Arreglo

       Precondición: fuente pertenece a Arreglo

       Poscondición: Para todo i, 0 <= i < n, elem[i] = fuente.elem[i]

    */

    Arreglo(Arreglo<TipoB> &fuente);

    /*

    Operación: Arreglo

        Descripción: Libera el espacio ocupado por el arreglo.

        Descripción operacional: Arreglo: Arreglo ->

        Precondición:

        Poscondición:

    */

    Arreglo() { delete elem; }

    /*

    Operación =

        Descripción: Asigna (copia) la información del arreglo fuente.

        Descripción operacional: =: Arreglo x Arreglo -> Arreglo

        Precondición: fuente pertenece a Arreglo

        Poscondición: Para todo i, 0<= i < n, elem[i] =fuente.elem[i]

    */

    Arreglo &operator =(Arreglo<TipoB> fuente);

    /*

    Operación [] 

        Descripción: Retorna una referencia a un elemento del arreglo.

        Descripción operacional: []: Arreglo x N -> TipoB 

        Precondición: i pertenece a N

        Poscondición: []=elem[i]

    */

    TipoB &operator [](int i);

    /*

    Operación tam

        Descripción: Retorna el tamaño del arreglo.

        Descripción operacional: tam: Arreglo -> N

        Precondición:

        Poscondición: tam=n

    */

    int tam() { return num; }

}; // template <class TipoB> class Arreglo

/*

Operación Arreglo

    Descripción: Crea un arreglo basado en un arreglo fuente.

    Descripción operacional: Arreglo: Arreglo -> Arreglo

    Precondición: fuente pertenece a Arreglo

    Poscondición: Para todo i, 0 <= i < n, elem[i] = fuente.elem[i]

*/

template<class TipoB> 

Arreglo<TipoB>::Arreglo(Arreglo<TipoB> &fuente)

{

    num = fuente.num;

    elem = new TipoB[num];

    // Si mo hay memoria

    if(elem == NULL){

        throw NoHayMemoria();

    }

    for(int i = 0; i < num; i++){

        elem[i] = fuente.elem[i];

    }

}

/*

Operación =

    Descripción: Asigna (copia) la información del arreglo fuente.

    Descripción operacional: =: Arreglo x Arreglo -> Arreglo

    Precondición: fuente pertenece a Arreglo

    Poscondición: Para todo i, 0<= i < n, elem[i] =fuente.elem[i]

*/

template<class TipoB> 

Arreglo<TipoB> &Arreglo<TipoB>::operator =(Arreglo<TipoB> fuente)

{

    delete elem;

    num = fuente.num;

    elem = new TipoB[num];

    // Si no hay memoria

    if(elem == NULL){

        throw NoHayMemoria();

    }

    for(int i = 0; i < num; i++){

        elem[i] = fuente.elem[i];

    }

}

/*

Operación []

    Descripción: Retorna una referencia a un elemento del arreglo.

    Descripción operacional: []: Arreglo x N -> TipoB

    Precondición: i pertenece a N

    Poscondición: []=elem[i]

*/

template<class TipoB> 

TipoB &Arreglo<TipoB>::operator [](int i)

{

    if(i < 0){

        throw FueraRango();

    }

    if(i < num){

        return elem[i];

    }

    // Crear un nuevo arreglo con el espacio suficiente.

    TipoB *nuevo = new TipoB[i + 1];

    // Si no hay memoria

    if(nuevo == NULL){

        throw NoHayMemoria();

    }

    // Pasar los elementos a  nuevo arreglo.

    for(int j = 0; j < num; j++){

        nuevo[j] = elem[j];

    }

    // Liberar el anterior arreglo de elementos.

    delete elem;

    elem = nuevo;

    num = i + 1;

    return elem[i];

} // TipoB &Arreglo::operator [](int i)

#endif

//--- Fin de arregloExc.h

Los cambios son realmente pocos, eso hace que valga la pena poner excepciones en la implementación. La primera diferencia está en el código:

// Excepciones:

class NoHayMemoria { }; // Excepción: No hay memoria.

class FueraRango { }; // Excepción: Fuera de rango.

Estas sentencias declaran dos clases, vacias, que serviran para ser lanzadas como excepciones. Las dos ecepciones tiene en cuenta el fuera de rango y que llegue a faltar memoria.

Otro cambio está en las funcion constructora:

template<class TipoB> 

Arreglo<TipoB>::Arreglo(Arreglo<TipoB> &fuente)

{

    num = fuente.num;

    elem = new TipoB[num];

    // Si no hay memoria

    if(elem == NULL){

        throw NoHayMemoria();

    }

    for(int i = 0; i < num; i++){

        elem[i] = fuente.elem[i];

    }

}

En esta se verifica que después de pedir memoria con el new esta operación termine normalmente. Esto es, si no hay memoria elem se hace nulo y se lanza con throw la excepción de NoHayMemoria. En la operación de asignación y en la de selecciónse hace lo mismo, pero miremos en detalle la operación de selección:

template<class TipoB> 

TipoB &Arreglo<TipoB>::operator [](int i)

{

    if(i < 0){

        throw FueraRango();

    }

    .

    .

    .

} // TipoB &Arreglo::operator [](int i)

En ella se verifica que el índice del arreglo no esté fuera de rango. Veamos como se manejen estas excepciones en un programa que use el Arreglo:

/*

arreglo_prueba.cpp

Autor: L. Alejandro Bernal R.

Fecha: 200.12.02

Descripción: Prueba del TDA arreglo.

*/

#include "arregloExc.h"

#include <iostream.h>

int main(void)

{

    try{

        Arreglo<int> arr;

        arr[10] = 67;

        arr[2] = 3;

        arr[20] = 345;

        Arreglo<int> arr2 = arr;

        Arreglo<int> arr3;

        arr3 = arr;

        arr[-1] = 345; // Produce la excepción FueraRango.

    }

    catch(Arreglo<int>::NoHayMemoria){

        cerr << "Error: No hay memoria\n";

        return 1;

    }

    catch(Arreglo<int>::FueraRango){

        cerr << "Error: Fuera de rango\n";

        return 1;

    }

    return 0;

}

//---- Fin arreglo_prueba.cpp

Este es muy similar al programa anterior, pero sin la impresión por salida estándar. El programa intenta try ejecutar un segmento de código, si este lanza throw la excepción esta es capturada por catch, fijese que es necesario un bloque catch por cada uno de los tipos de excepción que se lanzan.

En el programa anterior la captura de la excepción es simplemente imprimir por el error estándar y salir del programa con un código de error. En programas más profecionales es necesario un manejo de excepciónes más sofisticado.

La sentencia:

arr[-1] = 345;
produce a proposito una excepción para que el lector puede ver el comportamiento de esto en la ejecución del programa. Normalmente en C++ los subindices negativos no producen errores, pero gracias al manejo de excepciones hemos alterado el comportamiento del lenguaje. Podemos decir, entonces:

Se debe tener manejo de excepciones en las implementaciones de los TDAs para hacer más robustos nuestros programas.


next up previous contents
Next: Resumen Up: 5.2 Implementación Previous: 5.2.1 Una primera implementación   Contents
Ing. L. Alejandro Bernal R. 2001-01-18
Free Web Hosting