2009-11-10 14 views
5

I porto una aplicación de tamaño medio de C a C++. No trata en ningún lado con excepciones, y eso no debería cambiar.Evitar std :: bad_alloc. new debe devolver un puntero NULL

Mi (¡incorrecta!) Comprensión de C++ fue (hasta que lo aprendí de la manera difícil ayer) que el nuevo operador (predeterminado) devuelve un puntero NULL en caso de un problema de asignación. Sin embargo, eso solo fue cierto hasta 1993 (más o menos). Hoy en día, arroja una excepción std :: bad_alloc.

¿Es posible volver al comportamiento anterior sin volver a escribir todo para usar std :: nothrow en cada llamada?

+2

Le puede interesar leer esto: http://stackoverflow.com/questions/550451/will-new-return-null-in-any-case – Naveen

+6

Muerde la bala. Ve a arreglar tu código para usar std :: nothrow. awk y un par de expresiones regulares te darán el 90% del camino hasta allí. –

+0

+1 para cosas realmente reales para muchas personas a pesar de que estoy en contra de hacer tales cosas (y respondí a continuación por qué). –

Respuesta

11

Se podría sobrecargar el operador new:

#include <vector> 

void *operator new(size_t pAmount) // throw (std::bad_alloc) 
{ 
    // just forward to the default no-throwing version. 
    return ::operator new(pAmount, std::nothrow); 
} 

int main(void) 
{ 
    typedef std::vector<int> container; 

    container v; 
    v.reserve(v.max_size()); // should fail 
} 
+1

@GMan: en el ejemplo, la falla no está clara: ¿tiene la intención de mostrar la desventaja de utilizar nothrow? – stefaanv

+2

Esto probablemente fallará fatalmente.Los contenedores estándar se ocupan de la memoria utilizando el asignador (por defecto, el asignador estándar) y al menos uno de ellos espera que se genere una excepción cuando no hay memoria y no verificará el valor de retorno NULO. También esto no resuelve el problema del operador nuevo sobrecargado para una clase. Sin embargo, este es un problema poco probable teniendo en cuenta que el código se transporta desde C. –

+0

Sí, estaba destinado a ejecutarse "correctamente" sin excepciones. Y ten en mente el punto de Adam; básicamente estás volviendo a trabajar sobre cómo funciona 'operator new' en un error, y algunas personas confían en eso. Sin embargo, tú no eres uno de ellos. :) – GManNickG

0

su compilador es probable que tenga un interruptor de línea de comandos para activar/desactivar este comportamiento.

+2

una respuesta mucho más útil habría sido escribir el modificador de línea de comandos que supuestamente existe, al menos para gcc y VC++. –

3

Incluya el encabezado <new>. Contiene un "no-tiro" de la versión nueva puede utilizar como esto:

#include <new> 

int main() { 
    int* p = new(std::nothrow) int; 
    if (p) { 
     delete p; 
    } 
} 

Editar: admito que perdí la última frase de la cuestión. Pero para ser honesto, creo que ajustar "new simple" para tener un comportamiento previo a la norma tampoco es una buena idea. Buscaría algún tipo de búsqueda automática & reemplazar para convertir cada new en new(std::nothrow).

+2

que tipo de perdido el párrafo en negrita. –

+0

Sí, parece que sí. Me perdí la segunda mitad. – sellibitze

1

Lo siento, pero en cuanto a mi opinión, NO deberías hacer esto y volver al comportamiento anterior. Esto es porque simplemente no puede evitar excepciones de todos modos.

¿POR QUÉ?

Considere la posibilidad de una nueva llamada que debe asignar clase con el constructor llamando a un código de inicialización que necesita construir algo temporal que sea dinámico. Por desgracia, vas a tener una excepción. No importa si usa std :: nothrow. Este es solo un escenario entre el número de ellos.

En el libro de Scott Meyers Effective C++ se discutió en detalles por lo que recuerdo. Pero no estoy seguro si todos los casos son revisados ​​(pero sugiero que sean suficientes).

+0

Uso el constructor solo para asignaciones. Para cualquier cosa más, utilizo un método "bool Init()". – dmeister

+0

Las cosas siempre cambian. Podría suceder incluso después de dejar de apoyar este código y pasar al otro lado del globo. Solo noté que vi un número de casos en los que la gente confiaba demasiado en std :: nothrow. Pero no es magia ;-). –

1

Sólo probarlo:

1.Define una función que desea invocar en condición de falta de memoria.

2.Pass esta función para establecer la nueva función _handler para que cuando se produzca un nuevo error se llame a esta función.

+0

No estaba al tanto, pero el borrador estándar dice que 'new_handler' puede a) hacer que haya más memoria disponible y regresar, b) lanzar' std :: bad_alloc' o excepción derivada, c) llamar a abort() o salir(). Lo que no puedes hacer es hacer un nuevo retorno 0 en lugar de tirar. – UncleBens

Cuestiones relacionadas