Juguemos un rato con el siguiente código fuente:
1: #include "stdafx.h"
2: #include <Windows.h>
3:
4: int _tmain(int argc, _TCHAR* argv[])
5: {
6: HANDLE hHeap=HeapCreate(HEAP_GENERATE_EXCEPTIONS,0,4096);
7:
8: try
9: {
10: for(;;)
11: HeapAlloc(hHeap,HEAP_GENERATE_EXCEPTIONS,1024);
12: }
13: catch(...)
14: {
15: ;
16: }
17:
18: HeapDestroy(hHeap);
19: return 0;
20: }
El programa es muy sencillo: crea un montículo local de 4Kb (una página de RAM) y luego se vuelve loco asignando bloques de 1KB. Como buenos programadores de C++ que somos, encerramos la asignación de memoria dentro de un bloque try y capturamos cualquier excepción que se pueda producir. Luego liberamos de un plumazo el montículo asignado, sin preocuparnos de los bloques que hemos asignado (que es una de las ventajas de trabajar con montículos locales).
Evidentemente, cuando intentemos asignar un bloque que no quepa, la función lanzará una excepción, que será capturada por nuestro bloque catch, ¿no? (Dejaremos como ejercicio para el lector el hecho de que la excepción ocurra en la tercera iteración y no en la quinta).
Pues si no hemos tocado nada de las opciones del proyecto, no. Nos saltará el IDE con una excepción no controlada en lugar de nuestro bloque de captura… mmmmm… curioso.
¿Qué está ocurriendo? Básicamente que el modelo de excepciones de Windows no es el mismo que el de C++; es decir, las excepciones producidas o lanzadas dentro de las funciones Win32 no son directamente compatibles con C++, quizás porque cuando Windows se hizo… el C++ era un animal mitológico que solamente unos pocos gurús utilizaban y que en general consistía en un metacompilador que generaba código C, sin estandarización alguna. También pudo haberse debido a que como Win32 se programa directamente en C, no se esperaba que el C++ tuviera la importancia que ahora tiene.
Pero entonces, ¿cómo capturo una excepción Win32? En el C de Microsoft (y por extensión también en su C++, ignoro si otros compiladores también lo soportan), existen los bloques __try/__except/__finally, que realizan una especie de pseudocontrol de excepciones un tanto barroco, ya que los parámetros para el bloque __exceptse definen de una forma un tanto estrambótica.
Como este tipo de control de excepciones no se debe puede mezclar con el de C++, no vamos a entrar en detalles sobre su funcionamiento, sino que vamos a poner un enlace con un ejemplo: http://msdn2.microsoft.com/en-us/library/ms681409(VS.85).aspx. Y este otro con el punto de entrad en la MSDN sobre el tema: http://msdn2.microsoft.com/en-us/library/ms680657(VS.85).aspx.
Entonces, ¿qué? ¿Se puede o no se puede? Pues claro que se puede, tan sólo hay que cambiar una opción del proyecto.
Nos vamos a la pantalla de que estamos viendo en la captura de arriba, y cambiamos en Enable C++ Exceptions» la opción por defecto de «Yes (EHsc)» por la mostrada en la imagen.
¿Qué hemos hecho? Pues le hemos dicho al compilador que habilite la compatibilidad con las excepciones de Win32, de forma que, una vez compilado el ejemplo de arriba con esta opción activada, se nos disparará correctamente la excepción.
Según la documentación, se pierde algo de optimización agresiva en las excepciones, pero pienso que las ventajas superan a los inconvenientes, ya que hemos normalizado el control de las excepciones.