Mi rendo conto che sebbene la domanda non abbia alcun tag di lingua, probabilmente sta implicitamente parlando di "lingue del caffè". Ma solo per completezza, vorrei menzionare l'apparente consenso alquanto divergente nel mondo C ++.
Ci sono tre cose a cui i programmatori C ++ saranno generalmente interessati:
- Avrà overhead zero in build ottimizzate? (Cioè, può essere "compilato"?)
- Posso usarlo per intercettare un debugger proprio nel punto in cui è stato rilevato l'errore?
- Posso usarlo per segnalare problemi da funzioni dichiarate
noexcept
?
In passato, ho affrontato il primo problema scrivendo codice come questo
int
factorial(const int n)
{
if (CHECK_ARGS)
{
if (n < 0)
throw std::invalid_argument {"n < 0"};
}
int fac = 1;
for (int i = 2; i <= n; ++i)
fac *= i;
return fac;
}
dove CHECK_ARGS
è #define
d una costante di compilazione in modo che il compilatore possa eliminare completamente tutto l'argomento che controlla il codice in build ottimizzate. (Non sto dicendo che la compilazione dei check out sia una buona cosa in generale, ma credo che un utente dovrebbe avere la possibilità di compilarli.)
Mi piace ancora su questa soluzione che l'argomento che controlla il codice sia chiaramente visibile raggruppato insieme nel if
. Tuttavia, il secondo e il terzo problema non sono risolti da questo. Pertanto, ora mi sto appoggiando ancora di più all'utilizzo di una assert
macro per il controllo degli argomenti.
Gli standard di codifica Boost concordano con questo:
Che dire degli errori del programmatore?
Come sviluppatore, se ho violato un prerequisito di una libreria che sto usando, non voglio che lo stack si svolga. Quello che voglio è un core dump o l'equivalente - un modo per ispezionare lo stato del programma nel punto esatto in cui è stato rilevato il problema. Questo di solito significa assert()
o qualcosa del genere.
C'è stato un discorso molto interessante tenuto da John Lakos a CppCon'14 dal titolo Defensive Programming Done Right ( parte 1 , parte 2 ). Nella prima parte del suo discorso, discute della teoria dei contratti e del comportamento indefinito. Nella seconda parte, presenta quella che considero un'ottima proposta per il controllo sistematico degli argomenti. In sostanza, propone macro di asserzioni che consentono all'utente di selezionare la quantità di budget (in termini di utilizzo della CPU) che è disposta a donare alla biblioteca per la verifica degli argomenti e che la biblioteca fa un uso saggio di quel budget. Inoltre, l'utente può anche installare una funzione di gestione degli errori globale che verrà chiamata in caso di rilevamento di un contratto non funzionante.
Per quanto riguarda l'aspetto che una funzione è privata, non penso che ciò significhi che non dovremmo mai farla controllare i suoi argomenti. Potremmo fidarci maggiormente del nostro codice per non violare il contratto di una funzione interna, ma sappiamo anche che non siamo perfetti. Il controllo degli argomenti nelle funzioni interne è altrettanto utile nel rilevare i nostri bug come nelle funzioni pubbliche per rilevare i bug nel codice client.