5

La expresión new en el bloque try arroja una excepción bad_alloc en mi computadora.¿Cómo es que `e.what()` imprime "mala asignación"?

Tenga en cuenta que la cláusula de captura recibe un objeto de excepción por valor, no por referencia. ¿Cómo es que e.what() imprime "bad allocation"? Pensé que sería cortado.

#include <iostream> 

int main() 
{ 
    try 
    { 
     int* p = new int[0x1F000000]; 
    } 
    catch(std::exception e) 
    { 
     std::cout << e.what() << std::endl; 
    } 
} 
+2

Acabas de tratar de asignar = ~ 1.9375GB en tu programa. ¿Estás compilando 32 bits? ¿Tienes tanta RAM en tu máquina? – FailedDev

+0

@GMan El compilador es MS VS 2008 – Belloc

Respuesta

13

Visual Studio (Dinkumware?) Utiliza una implementación de std::exception que contiene † almacenamiento interno para el mensaje. (Completo con un constructor no estándar que acepta una cadena).

Debido a esto, no se necesita ningún despacho virtual para obtener el mensaje de error, ya que sobrevive a cualquier división.

Una implementación más ortodoxa de hecho imprimiría un mensaje de excepción genérico, porque el objeto derivado se cortó. (Efectivamente, MS ha hecho std::exception y std::runtime_error equivalente. No hay nada malo con esto, ya que el valor de retorno de std::exception::what es definido por la implementación, sino que explica sus resultados.)


† almacenamiento interno aquí se utiliza libremente. No tiene un buffer interno , pero tiene un const char* y un bool. El const char* apunta al mensaje (el valor de retorno de what()) y el bool es un indicador que determina si el búfer debe eliminarse.

Es como esto:

class msvc_exception // for exposition 
{ 
public: 
    msvc_exception(const char* msg) : 
    mMsg(msg), 
    mDoDelete(false) 
    {} 

    msvc_exception(const std::string& msg) : 
    mMsg(copy_string(msg)), 
    mDoDelete(true) 
    {} 

    virtual ~msvc_exception() 
    { 
     if (mDoDelete) 
      delete [] mMsg; 
    } 

    virtual const char* what() const throw() 
    { 
     return mMsg ? mMsg : "unknown"; 
    } 

private: 
    const char* copy_string(const std::string& str) 
    { 
     const char* result = new char[str.size() + 1]; 

     std::copy(str.begin(), str.end(), result); 
     result[str.size()] = 0; // null-terminate 

     return result; 
    } 
}; 

Ahora vemos que bad_alloc funciona así:

class msvc_bad_alloc : // for exposition 
     public msvc_exception 
    { 
    public: 
     msvc_bad_alloc() : 
     msvc_exception("bad_alloc") // note: a static string, no dynamic storage 
     {} 
    }; 

rebanar no afecta el mensaje porque el mensaje "existe" en la clase base.

Otros compiladores, como GCC y LLVM, aplicar un poco más recto hacia delante:

class orthodox_exception 
{ 
public: 
    orthodox_exception(){} 
    virtual ~orthodox_exception() {} 

    virtual const char* what() const throw() 
    { 
     return "orthodox_exception"; 
    } 
}; 

class orthodox_bad_alloc : 
    public orthodox_exception 
{ 
public: 
    const char* what() const throw() 
    { 
     return "orthodox_bad_alloc"; 
    } 
}; 

Aquí, rebanar afectaría a su resultado. (Dicho esto, después de todo esto: siempre capturas por referencia.)

+0

Entonces, ¿está diciendo que 'exception' conserva una copia de la cadena de caracteres para todas sus clases derivadas? – Belloc

+0

@ user1042389: Mi lenguaje estaba un poco suelto, permítanme editarlo. – GManNickG

+0

Muy claro ahora. Muchas gracias. – Belloc

Cuestiones relacionadas