2009-08-20 15 views
10

lo que el uso de Qt mucho con mi desarrollo y encanta. El patrón de diseño habitual con objetos Qt es asignarlos usando new.Política con std :: captura bad_alloc

Casi todos los ejemplos (especialmente el código generado por el diseñador de Qt) no comprueban absolutamente la excepción std::bad_alloc. Dado que los objetos asignados (generalmente widgets y demás) son pequeños, esto casi nunca es un problema. Después de todo, si no puede asignar algo así como 20 bytes, es probable que no haya mucho que pueda hacer para solucionar el problema.

Actualmente, he adoptado una política de ajuste de asignaciones "grandes" (cualquier cosa sobre una página o dos en tamaño) en un try/catch. Si eso no funciona, puedo mostrar un mensaje al usuario, casi cualquier cosa más pequeña, sólo voy a dejar que el accidente de aplicación con una excepción std::bad_alloc.

tanto, me pregunto lo que las escuelas de pensamiento sobre esto son en esto?

¿Es una buena política verificar todas y cada una de las operaciones new? ¿O solo los que espero tener el potencial de fallar?

Además, es claramente una historia completamente diferente cuando se trata de un entorno integrado donde los recursos pueden ser mucho más restringidos. Pregunto en el contexto de una aplicación de escritorio, pero también estaría interesado en respuestas que involucren otros escenarios.

Respuesta

17

El problema no es "dónde atrapar" sino "qué hacer cuando se atrapa una excepción".

Si desea comprobar, en lugar de envolver con try catch es mejor utilizar

#include <new> 
    x = new (std::nothrow) X(); 
    if (x == NULL) { 
     // allocation failed 
    } 

Mi práctica habitual es

  • en el programa no interactivo, la captura en el nivel principal una una pantalla mensaje de error adecuado allí.

  • en el programa que tiene un bucle de interacción con el usuario, también capté en el bucle para que el usuario pueda cerrar algunas cosas y tratar de continuar.

Excepcionalmente, hay otros lugares donde una captura es significativa, pero es rara.

+1

de hecho nothrow new es una opción viable, pero si hay algunas asignaciones en un bloque de código dado, será mucho más detallado que el simple uso de un bloque try/catch. Estoy totalmente de acuerdo en que "qué hacer" es la verdadera pregunta, ya que los escenarios sin memoria realmente limitan cuánto puede hacer para arreglar las cosas. –

+1

No tanto "qué hacer", sino "¿se puede hacer algo?" – jalf

+0

Si lo captas lo suficientemente alto, es posible que parte de la memoria se haya liberado durante el desenrollado de la pila. Puedes asegurarte de que algo se libere, utilizando un nuevo manipulador o trucos como 'int flag = false; try {vector v (1000); flag = verdadero; doEventLoop(); } catch (bad_alloc) {if (flag) cout << "Tengo 4k para usar para solicitar al usuario \ n"; } ' –

6

generalmente cojo excepciones en el punto donde el usuario ha iniciado una acción. Para la aplicación de consola que esto significa en main, para aplicaciones GUI puse manipuladores en lugares como el botón de clic manipuladores y tal.

creo que no tiene mucho sentido la captura de excepciones en la mitad de una acción, el usuario por lo general espera que la operación tiene éxito o falla por completo.

9

Maneje la excepción cuando puede. Si falla una asignación y su aplicación no puede continuar sin ese poco de memoria, ¿por qué molestarse en buscar el error?

Maneje el error cuando se puede manejar , cuando hay una manera significativa de recuperar. Si no hay nada que puedas hacer sobre el error, simplemente deja que se propague.

+0

Me gustaría aceptar tanto la suya como la de AProgrammer, ambas parecen ser buenas respuestas. Como AProgrammer fue el primero, estoy aceptando el suyo. –

+0

yup yup. El suyo es más detallado también – jalf

0

manejarlo en main() (o el controlador de la parte superior excepción de nivel equivalente en Qt)

La razón es que std :: bad_alloc o bien ocurre cuando se agota el espacio de memoria (2 o 3 GB en sistemas de 32 bits, doesn no sucede en sistemas de 64 bits) o cuando agota el espacio de intercambio. Los asignadores de montón modernos no están ajustados para ejecutarse desde el espacio de intercambio, por lo que será una muerte lenta y ruidosa; es probable que los usuarios eliminen su aplicación con mucha antelación ya que su interfaz de usuario ya no responde. Y en Linux, el manejo de la memoria del sistema operativo es tan pobre por defecto que es probable que su aplicación se elimine automáticamente.

Por lo tanto, hay poco que puede hacer. Confiese que tiene un error y vea si puede guardar cualquier trabajo que el usuario haya realizado. Para poder hacerlo, lo mejor es abortar tanto como sea posible. Sí, esto puede de hecho perder parte de la última entrada del usuario. Pero es esa misma acción la que probablemente desencadenó la situación OOM. El objetivo es guardar cualquier información en la que pueda confiar.

3

Este es un hilo relativamente antiguo, pero estaba a la altura cuando yo estaba buscando para las consideraciones "std :: bad_alloc" cuando se hace nueva/Eliminar anulando aquí en 2012.

no llevar el concepto "oh bueno, nada que puedas hacer de todos modos "como una opción viable. Personalmente uso en mis propias asignaciones el método "if (alloc()) {} else {error/handling}" mencionado anteriormente. De esta manera puedo manejar y/o informar adecuadamente cada caso en su propio contexto significativo.

Ahora, algunas otras soluciones posibles son: 1) Anule el nuevo/eliminar para la aplicación donde puede agregar su propio manejo de memoria insuficiente.

Aunque al igual que otros carteles de estado, y en particular sin conocimiento de los contextos particulares, la principal opción es, probablemente, para simplemente cerrar la aplicación. Si este es el caso, querrá que su controlador haya preasignado la memoria necesaria y/o utilice memoria estática, así que con suerte el manejador no se agotará.

Aquí podría tener, al menos, tal vez un estallido de diálogo y decir algo en la línea de: "La aplicación no tiene memoria Este es un error grave y debe ahora mismo por terminado La aplicación debe ejecutarse en el.. requisitos mínimos de memoria del sistema. Enviar informes de depuración a xxxx ". El controlador también podría guardar cualquier trabajo en progreso, etc., que ajuste la aplicación.

En cualquier caso no se desea utilizar esto para algo crítica, como (advertencia, humor de aficionados por delante): el transbordador espacial, un monitor de ritmo cardíaco, una máquina de diálisis de riñón, etc. Estas cosas requieren mucho más robusto soluciones por supuesto, usando fallas de cajas fuertes, métodos de recolección de basura de emergencia, 100% pruebas/depuración/borrosidad, etc.

2) Al igual que el primero, configure el global "set_new_handler()" con un controlador propio para atrapar la condición de falta de memoria en un ámbito global. Puede al menos manejar cosas como se menciona en el n. ° 1.

1

La verdadera pregunta es realtyty debería ¿tiene excepciones de std :: bad_alloc? En la mayoría de los casos, si se queda sin memoria, está condenado de todos modos y podría considerar finalizar su programa.

Cuestiones relacionadas