Tornati a scuola circa 10 anni fa, ti stavano insegnando a usare gli identificatori di eccezione. Dal momento che il mio background è uno di quei programmatori Torvaldish C che evita ostinatamente il C ++ a meno che non sia costretto a farlo, finisco sporadicamente in C ++ e, quando lo faccio, uso ancora gli identificatori di eccezioni poiché è quello che mi è stato insegnato.
Tuttavia, la maggior parte dei programmatori C ++ sembra disapprovare gli specificatori di eccezioni. Ho letto il dibattito e gli argomenti di vari guru del C ++, come questi . Per quanto ne capisco, si riduce a tre cose:
- Gli identificatori di eccezione utilizzano un sistema di tipi incompatibile con il resto della lingua ("sistema di tipi ombra").
- Se la tua funzione con un identificatore di eccezione genera qualcos'altro tranne quello che hai specificato, il programma verrà terminato in modi errati e inaspettati.
- Gli identificatori di eccezione verranno rimossi nel prossimo standard C ++.
Mi sto perdendo qualcosa qui o sono tutti questi i motivi?
Le mie opinioni:
Riguardo a 1): E allora. Il C ++ è probabilmente il linguaggio di programmazione più incoerente mai realizzato, in termini di sintassi. Abbiamo le macro, il goto / etichette, l'orda (accaparramento?) Di comportamenti non definiti / non specificati / definiti dall'implementazione, i tipi interi mal definiti, tutte le regole di promozione del tipo implicito, parole chiave per casi speciali come amico, auto , registrati, esplicito ... E così via. Qualcuno potrebbe probabilmente scrivere diversi libri spessi di tutte le stranezze in C / C ++. Quindi perché le persone reagiscono contro questa particolare incoerenza, che è un piccolo difetto rispetto a molte altre caratteristiche molto più pericolose della lingua?
Riguardo a 2): Non è mia responsabilità? Ci sono molti altri modi in cui posso scrivere un bug fatale in C ++, perché questo caso particolare è peggio? Invece di scrivere throw(int)
e poi lanciare Crash_t, posso anche affermare che la mia funzione restituisce un puntatore a int, quindi crea un typecast selvaggio ed esplicito e restituisce un puntatore a Crash_t. Lo spirito di C / C ++ è sempre stato quello di lasciare la maggior parte delle responsabilità al programmatore.
Che dire dei vantaggi allora? Il più ovvio è che se la tua funzione prova a lanciare esplicitamente qualsiasi tipo diverso da quello che hai specificato, il compilatore ti darà un errore. Credo che lo standard sia chiaro al riguardo (?). I bug si verificano solo quando la tua funzione chiama altre funzioni che a loro volta generano il tipo sbagliato.
Proveniente da un mondo di programmi C deterministici e integrati, preferirei sicuramente sapere esattamente quale funzione mi verrà lanciata. Se c'è qualcosa nella lingua che lo supporta, perché non usarlo? Le alternative sembrano essere:
void func() throw(Egg_t);
e
void func(); // This function throws an Egg_t
Penso che ci sia una grande possibilità che il chiamante ignori / dimentichi di implementare il try-catch nel secondo caso, meno nel primo caso.
A quanto ho capito, se una di queste due forme decide di lanciare improvvisamente un altro tipo di eccezione, il programma andrà in crash. Nel primo caso perché non è consentito lanciare un'altra eccezione, nel secondo caso perché nessuno si aspettava che generasse un SpanishInquisition_t e quindi quell'espressione non viene catturata dove avrebbe dovuto essere.
Nel caso di quest'ultimo, avere qualche ultima possibilità di cattura (...) al livello più alto del programma non sembra davvero migliore di un crash del programma: "Ehi, da qualche parte nel tuo programma qualcosa ha lanciato un'eccezione strana e non gestita . ". Non puoi ripristinare il programma una volta che sei così lontano da dove è stata generata l'eccezione, l'unica cosa che puoi fare è uscire dal programma.
E dal punto di vista dell'utente non potrebbe importare di meno se ricevono una finestra di messaggio malvagio dal sistema operativo che dice "Programma terminato. Blablabla all'indirizzo 0x12345" o una finestra di messaggio malvagia dal programma che dice "Eccezione non gestita: myclass. func.something". Il bug è ancora lì.
Con il prossimo standard C ++ non avrò altra scelta che abbandonare gli identificatori di eccezione. Ma preferirei ascoltare alcune solide argomentazioni sul perché siano cattive, piuttosto che "Sua Santità l'ha dichiarato e quindi è così". Forse ci sono più argomenti contro di loro rispetto a quelli che ho elencato, o forse c'è più per loro di quello che mi rendo conto?