domingo, 24 de mayo de 2015

*MANEJO DE EXCEPCIONES *LA CLASE STRING Y EL PROCESAMIENTO DE FLUJOS DE CADENA

              CENTRO UNIVERSITARIO UAEM 
              ATLACOMULCO
            LICENCIATURA EN INGENIERÍA EN COMPUTACIÓN

              NOMBRE DEL DOCENTE:
         INGENIERO. HÉCTOR CABALLERO HERNÁNDEZ

              NOMBRE MATERIA:
AUTÓMATAS Y LENGUAJES FORMALES

              NOMBRE DE LA ALUMNA:
HEIVILINA PÉREZ ARIAS

              GRUPO:
ICO-19

              TURNO:
MATÚTINO

               TRABAJO A ENTREGAR:
*MANEJO DE EXCEPCIONES
*LA CLASE STRING Y EL PROCESAMIENTO DE
FLUJOS DE CADENA
              FECHA DE ENTREGA:
21 DE ABRIL DE 2015.   

LA CLASE STRING Y EL PROCESAMIENTO DE FLUJOS DE CADENA
            Un objeto string se puede inicializar con un argumento constructor tal como string texto ( "Hola" ); // crea una cadena a partir de un const char * que crea un objeto string que contiene los caracteres en "Hola", o con dos argumentos constructores como en: string nombre( 8, 'x' ); que crea un objeto string que contiene ocho caracteres 'x'.
            La clase string también proporciona un constructor predeterminado (que crea una cadena vacía) y un constructor de copia. Una cadena vacía es un objeto string que no contiene caracteres.
            Un objeto string también se puede inicializar mediante la sintaxis constructora alternativa en su definición, como en: string mes = "Marzo"; // igual que: string mes( "Marzo" ); la clase string no proporciona conversiones de int o char a string en una definición string.
Por ejemplo, las definiciones
            string error1 = 'c';
            string error2( 'u' );
            string error3 = 22;
            string error4( 8 );
ASIGNACIÓN Y CONCATENACIÓN DE OBJETOS STRING
            [1]La función miembro at proporciona un acceso comprobado (o comprobación de rango); es decir, al ir más allá del final del objeto string se lanza una excepción out_of_range.
            La clase string también proporciona una versión sobrecargada de la función miembro assign que copia un número especificado de caracteres, como en cadenaDestino.assign( cadenaOrigen, inicio, numeroDeCaracteres ); en donde cadenaOrigen es el objeto string que se va a copiar, inicio es el subíndice inicial y numeroDeCaracteres es el número de caracteres a copiar.
COMPARACIÓN DE OBJETOS STRING
La clase string proporciona funciones miembro para comparar objetos string.
Todas las funciones operador sobrecargadas de la clase string que se demuestran aquí, así como las que no se demuestran aquí (!=, <, >= y <=), devuelven valores bool.
Demostración de las herramientas de comparación de cadena:
            string cadena1( "Probando las funciones de comparacion." );
             string cadena2( "Hola" );
             string cadena3( "probador" );
            string cadena4( cadena2 );

SUBCADENAS
            La clase string proporciona la función miembro substr para obtener una subcadena de un objeto string. El resultado es un nuevo objeto string que se copia del objeto string de origen.
Demostración de la función miembro substr:
            int main()
            {
            string cadena1( "El aeroplano aterrizo a tiempo." );
            cout << cadena1.substr( 7, 5 ) << endl;
            return 0;
            18 }
INTERCAMBIO DE OBJETOS STRING
            La clase string proporciona la función miembro swap para intercambiar objetos string.
            La función miembro swap de string es útil para implementar programas que ordenan cadenas.
Uso de la función swap para intercambiar dos objetos string:
            Antes Swap:
            Primero: uno
            Segundo: dos
            Después Swap:
            Primero: dos
            Segundo: uno
CARACTERÍSTICAS DE LOS OBJETOS STRING
            [2]La clase string proporciona funciones miembro para recopilar información acerca del tamaño de un objeto string, su longitud, capacidad, longitud máxima y otras características. El tamaño o la longitud de un objeto string es el número de caracteres actualmente almacenados en el objeto string.      La capacidad de un objeto string es el número de caracteres que se pueden almacenar en el objeto string sin necesidad de asignar más memoria. La capacidad de un objeto string debe ser cuando menos igual a su tamaño actual, aunque puede ser mayor. La capacidad exacta de un objeto string depende de la implementación. El tamaño máximo es el mayor tamaño posible que puede tener un objeto string. Si se excede este valor, se lanza una excepción length_error.
            [3]La función imprimirEstadisticas recibe una referencia a un objeto const string como argumento, e imprime la capacidad (usando la función miembro capacity), el tamaño máximo (usando la función miembro max_size), el tamaño (usando la función miembro size), la longitud (usando la función miembro length) y si el objeto string está o no vacío (usando la función miembro empty). La llamada inicial a imprimirEstadisticas indica que los valores iniciales para la capacidad, tamaño y longitud de cadena1 son 0.
            El tamaño y la longitud de 0 indican que no hay caracteres almacenados en un objeto string.
BÚSQUEDA DE SUBCADENAS Y CARACTERES EN UN OBJETO STRING
            La clase string proporciona funciones miembro const para buscar subcadenas y caracteres en un objeto string.
            Declaracion: La cadena cadena1 se declara y se inicializa. Después se trata de buscar "es" en cadena1, usando la función find. Si se encuentra "es", se devuelve el subíndice de la ubicación inicial de esa cadena. Si no se encuentra el objeto string, se devuelve el valor string::npos (una constante public static definida en la clase string).
            Se utiliza la función miembro find_first_of para localizar la primera ocurrencia en cadena1 de cualquier carácter en "liesop".
REEMPLAZO DE CARACTERES EN UN OBJETO STRING
            Se utiliza la función miembro erase de string para borrar todo, desde (e incluyendo a) el carácter en la posición x hasta el final de cadena1. [Nota: cada carácter de nueva línea ocupa un elemento en el objeto string].
            Se utiliza find para localizar cada ocurrencia del carácter de espacio. Después, cada espacio se reemplaza con un punto mediante una llamada a la función miembro replace de string.
             La función replace recibe tres argumentos: el subíndice del carácter en el objeto string en el que debe empezar el reemplazo, el número de caracteres a reemplazar y la cadena de reemplazo. La función miembro find devuelve string::npos cuando no se encuentra el carácter de búsqueda. Se utiliza la función find para buscar cada punto y otra función replace sobrecargada para reemplazar cada periodo y su siguiente carácter con dos signos de punto y coma.
            Los argumentos que se pasan a esta versión de replace son el subíndice del elemento en el que comienza la operación de reemplazo, el número de caracteres a reemplazar, una cadena de caracteres de reemplazo de la cual se selecciona una subcadena para utilizarla como caracteres de [4]reemplazo, el elemento en la cadena de caracteres en la que empieza la subcadena de reemplazo, y el número de caracteres en la cadena de caracteres de reemplazo que se debe utilizar.
INSERCIÓN DE CARACTERES EN UN OBJETO STRING
            La clase string proporciona funciones miembro para insertar caracteres en un objeto string.
Al utilizar string::npos, se inserta todo el objeto string.
Al utilizar string::npos, se inserta todo el objeto string.
Demostración de las funciones miembro insert de string.
            cadena3.insert( 3, cadena4, 0, string::npos );
CONVERSIÓN A CADENAS ESTILO C
            La clase string proporciona funciones miembro para convertir objetos de la clase string en cadenas basadas en apuntador estilo C. Como dijimos antes, a diferencia de las cadenas basadas en apuntador, los objetos string no tienen necesariamente una terminación nula. Estas funciones de conversión son útiles cuando una función dada recibe una cadena basada en apuntador como argumento.
            El objeto string cadena1 se inicializa con "cadenas", ptr1 se inicializa con 0 y longitud se inicializa con la longitud de cadena1. La memoria de un tamaño suficiente como para contener una cadena basada en apuntador equivalente al objeto string cadena1 se asigna en forma dinámica y se adjunta al apuntador char ptr2.
            Esta función miembro devuelve un arreglo de caracteres estilo C sin terminación nula.
ITERADORES
            La clase string proporciona iteradores para realizar recorridos hacia adelante y hacia atrás de objetos string. Los iteradores proporcionan acceso a los caracteres individuales con una sintaxis similar a las operaciones de los apuntadores.
No se comprueba el rango de los iteradores.
            El iterador iterador1 se inicializa al principio de cadena1 con la función miembro begin de la clase string. Existen dos versiones de begin: una que devuelve un iterator para iterar a través de un objeto string no const y una versión const que devuelve un const_iterator para iterar a través de un objeto const_string.
            La clase string proporciona las funciones miembro rend y rbegin para acceder a los caracteres individuales de un objeto string en forma inversa, desde el fi nal de un objeto string hacia su inicio. Las funciones miembro rend y rbegin devuelven objetos reverse_iterator o const_reverse_iterator (dependiendo de si el objeto string es no const o const).
PROCESAMIENTO DE FLUJOS DE CADENA
            Además de la E/S de f lujos estándar y la E/S de f lujos de archivos, en C++ la E/S de f lujos incluye herramientas para recibir datos de (y enviar datos a) objetos string en la memoria. A menudo, a estas herramientas se les conoce como E/S en memoria o procesamiento de flujos de cadena.
            [5]La entrada desde un objeto string está soportada por la clase istringstream. La salida hacia un objeto string está soportada por la clase ostringstream. Los nombres de las clases istringstream y ostringstream son en realidad alias definidos por las siguientes definiciones typedef:
            typedef basic_istringstream< char > istringstream;
            typedef basic_ostringstream< char > ostringstream;
            Las plantillas de clase basic_istringstream y basic_ostringstream proporcionan la misma funcionalidad que las clases istream y ostream, además de otras funciones miembro específi cas para el formato en memoria. Los programas que utilizan el formato en memoria deben incluir los archivos de encabezado <sstream> y <iostream>.
            Enviar datos a un objeto string es una buena forma de aprovechar las poderosas herramientas de formato de la salida de los f lujos de C++. Los datos se pueden preparar en un objeto string para imitar el formato de pantalla editado.
            Ese objeto string se podría escribir en un archivo en disco para preservar la imagen de la pantalla.
            Un objeto ostringstream utiliza un objeto string para almacenar los datos de salida. La función miembro str de la clase ostringstream devuelve una copia de ese objeto string.








MANEJO DE EXCEPCIONES
GENERALIDADES
      [6]El manejo de excepciones permite al programador remover el código para manejo de errores de la “línea principal” de ejecución del programa, lo cual mejora la claridad y capacidad de modificación del mismo. Esta flexibilidad reduce la probabilidad de que los errores se pasen por alto y, por consecuencia, hace que los programas sean más robustos.
                  Definición de una clase de excepción para representar el tipo del problema que podría ocurrir
      La clase runtime_error, una clase derivada de la clase exception de la Biblioteca estándar (definida en el archivo de encabezado <exception>), es la clase base estándar de C++ para representar errores en tiempo de ejecución.
La clase exception es la clase base estándar de C++ para todas las excepciones.
[7]Una clase de excepción típica que se deriva de la clase runtime_error define sólo un constructor  que pasa una cadena de mensaje de error al constructor de la clase base runtime_error. Cada clase de excepción que se deriva en forma directa o indirecta de exception contiene la función virtual what, la cual devuelve el mensaje de error de un objeto excepción. No es obligatorio derivar una clase de excepción personalizada (como ExcepcionDivision- EntreCero) de las clases de excepciones estándar que proporciona C++.
                  Encerrar código en un bloque try
      El manejo de excepciones está orientado a situaciones en las que la función que detecta un error no puede manejarlo.
      El lenguaje de C++ proporciona bloques try para permitir el manejo de excepciones. Un bloque try consiste en la palabra clave try, seguida de llaves ({}) que definen un bloque de código en el que podrían ocurrir errores. El bloque try encierra instrucciones que podrían ocasionar excepciones, e instrucciones que se deberían omitir si ocurre una excepción.
                  Definición de un manejador catch para procesar una excepcion division entre cero
      Las excepciones se procesan mediante los manejadores catch también conocidos como manejadores de excepciones, que atrapan y manejan las excepciones. Inmediatamente después de cada bloque try. Cada manejador catch empieza con la palabra clave catch y especifica entre paréntesis un parámetro de excepción que representa el tipo de excepción que puede procesar el manejador catch (en este caso, ExcepcionDivisionEntreCero).
      Cuando ocurre una excepción en un bloque try, el manejador catch que se ejecuta es aquél cuyo tipo coincide con el tipo de la excepción que ocurrió. Si un parámetro de excepción incluye un nombre de parámetro opcional, el manejador catch puede usar ese nombre de parámetro para interactuar con la excepción atrapada en el cuerpo del manejador catch, que está delimitado por llaves ({y}).
                  Modelo de terminación del manejo de excepciones
      Si ocurre una excepción como resultado de una instrucción en un bloque try, este bloque expira (termina de inmediato).El programa busca el primer manejador catch que pueda procesar el tipo de excepción que ocurrió. El programa localiza el catch que coincida, comparando el tipo de la excepción lanzada con el tipo del parámetro de excepción de cada catch, hasta que el programa encuentra una coincidencia.
                  Flujo del control del programa cuando el usuario escribe un denominador de cero
      [8]El operando de una instrucción throw puede ser de cualquier tipo. Si el operando es un objeto, lo llamamos objeto excepción; en este ejemplo, el objeto excepción es un objeto de tipo Excepcion Division Entre Cero. Un operando de throw también puede asumir otros valores, como el valor de una expresión que no produce un objeto (throw x > 5) o el valor de un int (por ejemplo, throw 5).
      En realidad, el manejador catch atrapa una referencia al objeto Error Division EntreCero creado por la instrucción throw de la función cociente. El objeto excepción se mantiene mediante el mecanismo de manejo de excepciones.
CUÁNDO UTILIZAR EL MANEJO DE EXCEPCIONES
      El manejo de excepciones no está diseñado para procesar los errores asociados con los eventos síncronos (por ejemplo, completar la E/S de disco, la llegada de mensajes de red, los clics del ratón y las pulsaciones de tecla), los cuales ocurren en paralelo con, y de manera independiente a, el f lujo de control del programa.
      El mecanismo de manejo de errores también es útil para procesar problemas que ocurren cuando un programa interactúa con los elementos de software, como las funciones miembro, los constructores, los destructores y las clases.
[9]     Las funciones con condiciones de errores comunes deben devolver 0 o NULL (u otros valores apropiados), en vez de lanzar excepciones. Un programa que llame a dicha función puede comprobar el valor de retorno para determinar si la llamada a la función tuvo éxito o fracasó.
VOLVER A LANZAR UNA EXCEPCIÓN
      Es posible que un manejador de excepciones, al momento de recibir una excepción, decida que no puede procesar esa excepción o que puede procesar la excepción sólo de manera parcial.      En tales casos, el manejador de excepciones puede diferir el manejo de excepciones a otro manejador de excepciones. En cualquier caso, para lograr esto hay que volver a lanzar la excepción mediante la siguiente instrucción:
throw;
ESPECIFICACIONES DE EXCEPCIONES
      Una especificación de excepciones opcional también conocida como lista throw enumera una lista de excepciones que puede lanzar una función. Por ejemplo, se considera la siguiente Declaración de una función:
      int unaFuncion( double valor )
      throw ( ExcepcionA, ExcepcionB, ExcepcionC )
      {
      }
      La especificación de la función, que empieza con la palabra clave throw justo después del paréntesis de cierre de la lista de parámetros de la función, indica que la función unaFuncion puede lanzar excepciones de los tipos ExcepcionA, ExcepcionB y ExcepcionC.
      Una función sólo puede lanzar excepciones de los tipos indicados por la especificación, o excepciones de cualquier tipo derivado de estos tipos. Si la función lanza (throw) una excepción que no pertenezca a un tipo especificado, el mecanismo de manejo de excepciones llama a la función unexpected, la cual termina el programa.
      Una función que no proporciona una especificación de excepciones puede lanzar cualquier excepción. Al colocar throw() (una especificación de excepciones vacía) después de la lista de parámetros de una función, se establece que esa función no lanza excepciones. Si la función intenta lanzar una excepción, se invoca la función unexpected.


PROCESAMIENTO DE EXCEPCIONES INESPERADAS
      La función unexpected llama a la función registrada con la función set_unexpected (definida en el archivo de encabezado <exception>). Si no se ha registrado una función de esta forma, se hace una llamada a la función terminate de manera predeterminada.
      Las funciones set_terminate y set_unexpected devuelven un apuntador a la última función llamada por terminate y unexpected, respectivamente (0, la primera vez que se llama a cada una). Esto permite al programador guardar el apuntador a la función, para poder restaurarlo más adelante. Las funciones set_terminate y set_unexpected reciben como argumentos apuntadores a funciones con tipos de valores de retorno void y sin argumentos.
LIMPIEZA DE LA PILA
      Limpiar la pila de llamadas a funciones significa que la función en la que no se atrapó la excepción termina, todas las variables locales en la función se destruyen y el control regresa a la instrucción que invocó originalmente a esa función. Si un bloque try encierra esa instrucción, se hace un intento de atrapar la excepción. Si un bloque try no encierra esa instrucción, se vuelve a realizar la limpieza de la pila.
      El constructor no puede devolver un valor para indicar un error, debemos elegir un medio alternativo de indicar que el objeto no se ha construido en forma apropiada. Un esquema es devolver el objeto mal construido y esperar que alguien que lo use realice las pruebas apropiadas para determinar que se encuentra en un estado inconsistente. Otro esquema es establecer una variable fuera del constructor.
      Una excepción podría impedir la operación de código que por lo general liberaría un recurso, con lo cual se produciría una fuga de recursos. Una técnica para resolver este problema es inicializar un objeto local para adquirir el recurso.
      [10]Cuando ocurra una excepción, se invocará al destructor para ese objeto y se podrá liberar el recurso.
EXCEPCIONES Y HERENCIA
      El uso de la herencia con excepciones permite a un manejador de excepciones atrapar los errores relacionados con una notación concisa. Una metodología es atrapar cada tipo de apuntador o referencia a un objeto excepción de clase derivada en forma individual, pero una metodología más concisa es atrapar mejor apuntadores o referencias a objetos excepción de la clase base.
      Además, al atrapar apuntadores o referencias a objetos excepción de una clase derivada se pueden cometer errores, en especial si el programador olvida evaluar de manera explícita uno o más de los tipos apuntador o referencia de la clase derivada.
PROCESAMIENTO DE LAS FALLAS DE NEW
      El estándar de C++ especifica que, cuando falla el operador new, lanza una excepción bad_alloc (definida en el archivo de encabezado <new>). Algunos compiladores no están en conformidad con el estándar de C++, y por lo tanto utilizan la versión de new que devuelve 0 al fallar.
Los compiladores varían en cuanto a su soporte para el manejo de fallas de new.
                  Manejo de las fallas de new mediante la función set_new_handler
      Una característica adicional para manejar las fallas de new es la función set_new_handler (cuyo prototipo se encuentra en el archivo de encabezado estándar <new>). Esta función recibe como argumento un apuntador a una función que no recibe argumentos y devuelve void. Este apuntador apunta a la función que se llamará si new falla. Esto proporciona al programador una metodología uniforme para manejar todas las fallas de new, sin importar que ocurra una falla en el programa.
      [11]Una vez que set_new_handler registra un manejador de new en el programa, el operador new no lanza bad_alloc en el futuro; en vez de ello, difiere el manejo de errores a la función manejadora de new.
      Si new asigna memoria con éxito, devuelve un apuntador a esa memoria.
LA CLASE AUTO_PTR Y LA ASIGNACIÓN DINÁMICA DE MEMORIA
      Un objeto de la clase auto_ptr mantiene un apuntador a la memoria que se asigna en forma dinámica. Cuando se hace una llamada al destructor de un objeto auto_ptr (cuando un objeto auto_ptr queda fuera de alcance), realiza una operación delete con su miembro de datos apuntador.
      La plantilla de clase auto_ptr proporciona los operadores sobrecargados * y ->, de manera que un objeto auto_ptr se puede utilizar de la misma forma que una variable apuntador común.
      Sólo un objeto auto_ptr puede poseer un objeto asignado en forma dinámica en un momento dado, y el objeto no puede ser un arreglo. Al usar su operador de asignación sobrecargado o su constructor de copia, un objeto auto_ptr puede transferir la propiedad de la memoria dinámica que maneja. El último objeto auto_ptr que mantiene el apuntador a la memoria dinámica eliminará la memoria.
JERARQUÍA DE EXCEPCIONES DE LA BIBLIOTECA ESTÁNDAR
      La experiencia ha demostrado que las excepciones se pueden clasificar en varias categorías.         La Biblioteca estándar de C++ incluye una jerarquía de clases de excepciones. Las clases derivadas inmediatas de la clase base exception incluyen a runtime_error y logic_error (ambas definidas en el encabezado <stdexcept>), cada una de las cuales tiene varias clases derivadas. De exception también se derivan las excepciones lanzadas por los operadores de C++; clase logic_error es la clase base de varias clases de excepciones estándar que indican errores en la lógica del programa.
      Por ejemplo, la clase invalid_argument indica que se pasó un argumento inválido a una función. (Sin duda, la codificación apropiada puede evitar que lleguen argumentos inválidos a una función). La clase length_error indica que para ese objeto se utilizó una longitud mayor que el tamaño máximo permitido para el objeto que se está manipulando.
      [12]La clase runtime_error, es la clase base de varias otras clases de excepciones estándar que indican errores en tiempo de ejecución. Por ejemplo, la clase overflow_error describe un error de desbordamiento aritmético (es decir, el resultado de una operación aritmética es mayor que el número más grande que se puede almacenar en la computadora) y la clase underflow_error describe un error de subdesbordamiento.
OTRAS TÉCNICAS PARA MANEJAR ERRORES
      Ignorar la excepción. Si ocurre una excepción, el programa podría fallar como resultado de la excepción que no se atrapó. Esto es devastador para los productos de software comerciales y el software de misión crítica y propósito especial, pero para el software desarrollado para nuestros propios fines, es común ignorar muchos tipos de errores:
      1.-Abortar el programa. Sin duda, esto evita que un programa se ejecute hasta completarse y que produzca resultados incorrectos. Para muchos tipos de errores esta técnica es apropiada, en especial para los errores no fatales que permiten a un programa ejecutarse hasta completarse (con lo cual el programador podría pensar que el programa funciona correctamente).
      2.-Establecer indicadores de errores. El problema con esta metodología es que los programas tal vez no comprueben estos indicadores de errores en todos los puntos en los que los errores podrían resultar problemáticos.
      3.-Probar la condición de error, generar un mensaje de error y llamar a exit (en <cstdlib>) para pasar un código de error apropiado al entorno del programa.
      4.-Usar las funciones setjump y longjump. Estas funciones de la biblioteca <csetjump> permiten al programador especificar un salto inmediato, desde una llamada a una función con muchos niveles de anidamiento hasta un manejador de errores.
REFERENCIA BIBLIOGRAFICA:
DEITEL, HARVEY M. Y PAUL J. DEITEL
Cómo programar en C++. Sexta edición.
PEARSON EDUCACIÓN, México 2008.
 




No hay comentarios:

Publicar un comentario