try {
int* p = 0;
*p = 1;
} catch (...) {
cout << "null pointer." << endl;
}
ho cercato di intercettare l'eccezione come questo, ma non funziona, qualsiasi aiuto?Come catturare l'eccezione puntatore nullo?
try {
int* p = 0;
*p = 1;
} catch (...) {
cout << "null pointer." << endl;
}
ho cercato di intercettare l'eccezione come questo, ma non funziona, qualsiasi aiuto?Come catturare l'eccezione puntatore nullo?
Non c'è nulla come "eccezione puntatore null" in C++. Le uniche eccezioni si può prendere, è le eccezioni esplicitamente generate da throw
espressioni (più, come ha osservato Pavel, alcune eccezioni C++ standard, generate dalla norma intrinsecamente operator new
, dynamic_cast
ecc). Non ci sono altre eccezioni in C++. Dereferenziamento di puntatori nulli, divisione per zero ecc. Non genera eccezioni in C++, produce comportamento non definito. Se si desidera eccezioni generate in casi del genere, è responsabilità dell'utente rilevare manualmente queste condizioni e fare esplicitamente throw
. È così che funziona in C++.
Qualunque cosa ti sembra di essere alla ricerca di è nota a che fare con il linguaggio C++, ma piuttosto una caratteristica di particolare implementazione. In Visual C++, ad esempio, le eccezioni di sistema/hardware possono essere "convertite" in eccezioni C++, ma c'è un prezzo collegato a questa funzionalità non standard, che normalmente non vale la pena pagare.
"Le uniche eccezioni si può prendere, è le eccezioni esplicitamente generate da espressioni tiro" - e di default 'operatore new' (può essere implementato usando esplicito' throw', certo, ma non c'è niente che lo richiede per farlo, ma può beh essere un intrinseco). –
Ci sono più posti in C++ che possono lanciare oltre a 'operator new',' dynamic_cast' per fare riferimento al tipo che è un altro esempio, ma non era questo il punto. Il punto è che puoi catturare solo eccezioni C++. Ovviamente, affermare che possono essere lanciati solo da un "lancio" a livello di utente non è corretto. – AnT
Il dereferenziamento di un puntatore/divisione nullo per zero non produce un comportamento non definito. Genera un'eccezione, con la differenza che si tratta di un'eccezione del sistema operativo, non di un C++. – Michael
Non è possibile. De-referenziare un puntatore nullo è una cosa di sistema.
Su Linux, il SO solleva i segnali nell'applicazione. Dai uno sguardo allo csignal per vedere come gestire i segnali. Per "catturare" uno, si aggancia una funzione in che verrà chiamata nel caso di SIGSEGV
. Qui puoi provare a stampare alcune informazioni prima di terminare con grazia il programma.
Windows utilizza structured-exception-handling. È possibile utilizzare le informazioni __try/__except
, come indicato nel collegamento precedente. Il modo in cui l'ho fatto in una certa utilità di debug che ho scritto era con la funzione _set_se_translator
(perché combacia strettamente con gli hook). In Visual Studio, assicurati di avere attivato SEH. Con questa funzione, è possibile collegare una funzione per chiamare quando il sistema solleva un'eccezione nell'applicazione; nel tuo caso lo chiamerebbe con EXCEPTION_ACCESS_VIOLATION
. È quindi possibile generare un'eccezione e farla propagare di nuovo come se fosse stata generata un'eccezione in primo luogo.
Devi anche usare '/ EHa' quando usi' _set_se_translator'. –
Ehi, ho detto che: P – GManNickG
Trovo che '_set_se_translator' è solo di uso limitato perché (da msdn) ..." In un ambiente multithreading, le funzioni del traduttore sono mantenute separatamente per ogni thread. Ogni nuovo thread deve installare il proprio funzione traduttore, quindi ogni thread è responsabile della propria gestione della traduzione, _set_se_translator è specifico per un thread, un'altra DLL può installare una funzione di traduzione diversa. " ... Quindi se non controlli la creazione di tutti i thread che chiamano il tuo codice non puoi usarlo. Detto questo, boost.test lo utilizza con grande effetto, ma questo è single threaded – iain
C++ non esegue il controllo puntatore (anche se suppongo che alcune implementazioni potrebbero). Se si tenta di scrivere su un puntatore nullo, è molto probabile che si verifichi un arresto anomalo. Non genererà un'eccezione. Se vuoi prenderlo devi controllare tu stesso il valore del puntatore prima di provare a scrivere su di esso.
Dipende davvero dall'implementazione e dal sistema operativo. Per esempio. su Win32, il dereferenziamento di un puntatore nullo si tradurrà in una violazione di accesso (come qualsiasi altra piattaforma con protezione della memoria, in realtà), ma Win32 AV è un'eccezione strutturata e può essere catturata da un compilatore C++ che implementa il proprio modello di eccezione in cima di Win32 SEH - ad esempio, VC++ con flag di compilazione '/ EHa'. Certo, è ancora malvagio (e non vendibile). –
Parlando di protezione della memoria, ho iniziato a scrivere C su DOS, quando scrivere su un puntatore nullo significava in genere riavviare il computer. Almeno DOS è stato avviato abbastanza velocemente. –
@Nate C-K: Una volta ho incasinato alcuni suggerimenti in un programma C su DOS e prima di appendere il computer ho stampato il contenuto della ROM. O almeno è così che ho interpretato quello che ho visto sullo schermo. – Giorgio
Dereferenziare un nullo (o puntatore che è passato alla fine di un array o un puntatore nullo casuale) determina un comportamento indefinito. Non c'è un modo portatile per "catturarlo".
Come altri hanno già detto, non è possibile farlo in C++.
Se posso fare un punto più ampio: anche in un linguaggio che permette di prenderlo, l'azione migliore è quella di non toccare puntatori nulli. Catturare un errore quando è già esploso in faccia, quindi decidere di andare avanti come non è successo, non è una buona strategia di codifica. Cose come la dereferenziazione del puntatore nullo, l'overflow dello stack, ecc., Dovrebbero essere viste come eventi catastrofici e evitate difensivamente, anche se il tuo linguaggio ti consente di reagire in modo diverso.
Non esiste un modo indipendente dalla piattaforma per eseguire questa operazione. Sotto Windows/MSVC++ è possibile utilizzare __try/__ eccetto
Ma non lo consiglierei comunque. Quasi certamente non è possibile ripristinare correttamente da un errore di segmentazione.
Si sta chiedendo specificatamente la dereferenziazione del puntatore nullo, che è sicuramente abbastanza recuperabile (in quanto non danneggia la memoria, ecc.). Ancora non è una buona idea, ma per ragioni diverse. –
In effetti, l'unica eccezione che ho avuto un po 'di difficoltà dal recupero è stata una overflow dello stack. In realtà, non potevo. Non penso sia possibile, poiché lanciare un'eccezione utilizza troppa pila, almeno su Windows (Linux fornisce uno stack alternativo per le eccezioni). Hai abbastanza tempo per generare un nuovo thread e provare a salvare quante più informazioni possibili, comunque. – GManNickG
Non sono d'accordo che sia recuperabile, dal momento che rappresenta un errore logico nel programma e l'unico modo per correggere gli errori logici è quello di modificare il programma stesso. È intercettabile, ma tracciabile non significa recuperabile. Se il programma rileva un errore logico, come questo, dovrebbe arrestarsi in modo anomalo prima del tempo, causando arresti anomali. – DrPizza
Generalmente non è possibile. Anche se potessi, sarebbe come cercare di mettere un cerotto su un sottomarino che è saltato fuori.
Un'applicazione danneggiata può fare molto più danni di una che si è schiantata. Il mio consiglio qui sarebbe di lasciarlo in crash, quindi correggere il motivo per cui è andato in crash. Risciacquare. Ripetere.
E grazie a Dio anche per questo. Questo in realtà rende i programmatori migliori e un codice migliore, penso. –
C'è un modo molto semplice per catturare qualsiasi tipo di eccezione (divisione per zero, violazione di accesso, etc.) in Visual Studio usando try
->catch (...)
blocchi.
Un piccolo ritocco del progetto è sufficiente. Basta abilitare l'opzione /EHa
nelle impostazioni del progetto. Vedere le proprietà del progetto -> C/C++ -> Generazione codice -> Modificare le eccezioni Abilita C++ su "Sì con eccezioni SEH". Questo è tutto!
Vedi dettagli qui: http://msdn.microsoft.com/en-us/library/1deeycx5(v=vs.80).aspx
Se si voleva si poteva solo fare il puntatore controllare voi stessi e gettare ...
if (p == nullptr) throw std::exception("woot! a nullptr!")
p->foo();
così naturalmente questo sarebbe solo per eseguire il debug del problema, il nullptr non dovrebbe verificarsi in primo luogo :)
Risposta breve: non è possibile in un modo portatile o standard, poiché i bug di questo tipo sono potenzialmente in grado di corrompere il processo stesso.
Risposta lunga: si può fare più di quanto si pensi, e sicuramente più del default del programma che si blocca. Tuttavia, è necessario tenere a mente 3 aspetti:
1) Questi bug sono PIÙ gravi delle eccezioni e spesso non possono presentare eccezioni alla logica.
2) Il rilevamento e la gestione della libreria saranno dipendenti dalla piattaforma sul back-end, anche se è possibile fornire un'interfaccia astratta e pulita per il consumo pubblico.
3) Ci saranno sempre dei crash che sono così brutti che non si riesce nemmeno a individuarli prima della fine.
Fondamentalmente, errori come segofault o danneggiamento dell'heap non sono un'eccezione perché stanno corrompendo il processo effettivo che esegue il programma. Qualunque cosa tu abbia codificato nel programma è parte del programma, inclusa la gestione delle eccezioni, quindi qualsiasi cosa che non sia la registrazione di un bel messaggio di errore prima che il processo muoia è sconsigliabile nei pochi casi in cui non è impossibile. In POSIX, il sistema operativo utilizza un sistema di segnalazione per segnalare errori come questi ed è possibile registrare le funzioni di callback per registrare l'errore prima di uscire. In Windows, il sistema operativo può a volte convertirli in eccezioni dall'aspetto normale da cui è possibile recuperare e recuperare.
In definitiva, tuttavia, la soluzione migliore è codificare in modo difensivo contro tali incubi. Su qualsiasi sistema operativo ci saranno alcuni che sono così cattivi che non è possibile rilevarli, anche in linea di principio, prima che il processo muoia. Ad esempio, corrompendo il proprio puntatore dello stack è qualcosa che può causare un crash così grave che persino i tuoi callback del segnale POSIX non lo vedono mai.
In VC++ 2013 (e versioni precedenti anche) si può mettere i punti di interruzione sulle eccezioni: + Canc (si aprirà la finestra di eccezione)
Ora eseguire il debug di nuovo, un punto di interruzione verrà colpito esattamente quando si è verificata la dereferenza nulla.
Non esiste alcuna eccezione di puntatore NULL in C++ ma si desidera catturare lo stesso, quindi è necessario fornire la propria implementazione di classe per lo stesso.
di seguito è l'esempio per lo stesso.
class Exception {
public:
Exception(const string& msg,int val) : msg_(msg),e(val) {}
~Exception() {}
string getMessage() const {return(msg_);}
int what(){ return e;}
private:
string msg_;
int e;
};
basa ora su puntatore NULL controllare può essere gettato come, throw(Exception("NullPointerException",NULL));
e sotto è il codice per la cattura lo stesso.
catch(Exception& e) {
cout << "Not a valid object: " << e.getMessage()<< ": ";
cout<<"value="<<e.what()<< endl;
}
Per VC++ in particolare, 'catch (...)' catturerà AV se si compila con 'cl.exe/EHa'. Tuttavia, se mai lo fai, un dio C++ arrabbiato ti colpirà immediatamente con un lampo sul posto, quindi dimentica che te l'ho detto. –
Evitare il crash del mio programma, o rimanere abbattuto da un fulmine. Un dilemma di un vecchio programmatore. –
Non confondere le eccezioni C++ con il sistema con il nome di sistema scaduto "eccezioni". –