Come mai `e.what ()` stampe “cattiva allocazione”?
-
26-10-2019 - |
Domanda
L'espressione new
nel blocco try
getta un bad_alloc
exception nel mio computer.
Si noti che la clausola catch riceve un oggetto eccezione per valore, non per riferimento. Come mai le stampe e.what()
"bad allocation"
? Ho pensato che sarebbe essere affettato.
#include <iostream>
int main()
{
try
{
int* p = new int[0x1F000000];
}
catch(std::exception e)
{
std::cout << e.what() << std::endl;
}
}
Soluzione
Visual Studio (Dinkumware?) Utilizza un'implementazione di std::exception
che contiene memoria interna † per il messaggio. (Completo di un costruttore non standard che accetta una stringa.)
A causa di questo, non la spedizione virtuale è effettivamente necessario per ottenere il messaggio di errore, sopravvive alcun taglio.
Un'implementazione più ortodosso sarebbe davvero stampare un messaggio di eccezione generica, perché l'oggetto derivato è stata tagliata fuori. (In effetti, MS ha fatto std::exception
e std::runtime_error
equivalente. Non c'è niente di sbagliato in questo, dal momento che il valore di ritorno di std::exception::what
è definito dall'implementazione, ma spiega i risultati.)
† Memoria interna qui è usato impropriamente. Essa non ha un interno di buffer , ma ha un const char*
e bool
. I punti const char*
al messaggio (il valore di ritorno di what()
), e il bool
è una bandiera determinare se il buffer deve essere eliminato.
E 'in questo modo:
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;
}
};
Vedete ora che funziona bad_alloc
come questo:
class msvc_bad_alloc : // for exposition
public msvc_exception
{
public:
msvc_bad_alloc() :
msvc_exception("bad_alloc") // note: a static string, no dynamic storage
{}
};
affettare non influenza il messaggio perché il messaggio "esiste" nella classe base.
Altri compilatori, come GCC e LLVM, implementare un po 'più dritto in avanti:
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";
}
};
Qui, affettare interesserebbe il vostro risultato. (Detto questo, dopo tutto questo:. Sempre prendere per riferimento)