Dovrebbero esserci affermazioni nelle build di rilascio


20

Il comportamento predefinito di assertin C ++ è di non fare nulla nelle build di rilascio. Presumo che ciò avvenga per motivi di prestazioni e forse per impedire agli utenti di visualizzare messaggi di errore negativi.

Tuttavia, direi che quelle situazioni in cui un assertavrebbe sparato ma era disabilitato sono ancora più problematiche perché l'applicazione probabilmente si arresterà in modo ancora peggiore lungo la linea perché alcuni invarianti sono stati rotti.

Inoltre, l'argomento delle prestazioni per me conta solo quando si tratta di un problema misurabile. La maggior parte dei messaggi assertnel mio codice non sono molto più complessi di

assert(ptr != nullptr);

che avrà un piccolo impatto sulla maggior parte del codice.

Questo mi porta alla domanda: le asserzioni (ovvero il concetto, non l'implementazione specifica) dovrebbero essere attive nelle build di rilascio? Perchè no)?

Si noti che questa domanda non riguarda come abilitare gli asserti nelle build di rilascio (come #undef _NDEBUGo usando un'implementazione di asserzione definita dall'utente). Inoltre, non si tratta di abilitare asserzioni nel codice di libreria standard / di terze parti ma nel codice da me controllato.


Conosco un attore globale nel mercato della sanità che ha installato una versione di debug del loro sistema informativo ospedaliero presso i siti dei clienti. Avevano un accordo speciale con Microsoft per installare anche lì le librerie di debug C ++. Bene, la qualità del loro prodotto era ...
Bernhard Hiller il

2
C'è un vecchio detto che dice "rimuovere le asserzioni è un po 'come indossare un giubbotto di salvataggio per esercitarsi nel porto, ma poi lasciare i giubbotti di salvataggio quando la nave parte per l'oceano aperto" ( wiki.c2.com/?AssertionsAsDefensiveProgramming ) . Personalmente li mantengo abilitati nelle build di rilascio per impostazione predefinita. Sfortunatamente, questa pratica non è molto comune nel mondo C ++, ma almeno il famoso veterano del C ++ James Kanze ha sempre sostenuto a favore di mantenere affermazioni nelle build di rilascio: stackoverflow.com/a/12162195/3313064
Christian Hackl

Risposte:


20

Il classico assertè uno strumento della vecchia libreria C standard, non di C ++. È ancora disponibile in C ++, almeno per motivi di compatibilità con le versioni precedenti.

Non ho una cronologia precisa delle librerie C standard a portata di mano, ma sono abbastanza sicuro che assertfosse disponibile poco dopo il momento in cui K&R C è entrato in funzione (intorno al 1978). Nel classico C, per scrivere programmi robusti, l'aggiunta di test puntatore NULL e il controllo dei limiti dell'array devono essere eseguiti molto più frequentemente rispetto al C ++. Il test al lordo dei puntatori NULL può essere evitato usando riferimenti e / o puntatori intelligenti anziché puntatori e std::vector, usando , il controllo dei limiti dell'array è spesso superfluo. Inoltre, il successo delle prestazioni del 1980 era decisamente molto più importante di oggi. Quindi penso che sia molto probabilmente il motivo per cui "assert" è stato progettato per essere attivo solo nelle build di debug per impostazione predefinita.

Inoltre, per la reale gestione degli errori nel codice di produzione, una funzione che verifica solo alcune condizioni o invarianti e blocca il programma se la condizione non è soddisfatta, nella maggior parte dei casi non è abbastanza flessibile. Per il debug probabilmente va bene, dal momento che chi esegue il programma e osserva l'errore ha in genere un debugger a portata di mano per analizzare cosa succede. Per il codice di produzione, tuttavia, una soluzione ragionevole deve essere una funzione o un meccanismo che

  • verifica alcune condizioni (e interrompe l'esecuzione nell'ambito in cui la condizione ha esito negativo)

  • fornisce un chiaro messaggio di errore nel caso in cui la condizione non sia valida

  • consente all'ambito esterno di accettare il messaggio di errore e di inviarlo a un canale di comunicazione specifico. Questo canale potrebbe essere qualcosa come stderr, un file di registro standard, una finestra di messaggio in un programma GUI, un errore generale nella gestione della richiamata, un canale di errore abilitato alla rete o qualunque cosa si adatti meglio al particolare software.

  • consente all'ambito esterno su base caso per caso di decidere se il programma deve terminare con grazia o se deve continuare.

(Naturalmente, ci sono anche situazioni in cui terminare immediatamente il programma in caso di una condizione non soddisfatta è l'unica opzione sensata, ma in questi casi dovrebbe accadere anche in una build di rilascio, non solo in una build di debug).

Dal momento che il classico assertnon fornisce queste funzionalità, non è adatto per una build di rilascio, supponendo che la build di rilascio sia ciò che si distribuisce nella produzione.

Ora puoi chiedere perché non esiste una tale funzione o meccanismo nella lib standard C che fornisce questo tipo di flessibilità. In realtà, in C ++, esiste un meccanismo standard che ha tutte queste caratteristiche (e molte altre), e tu lo sai: si chiama eccezioni .

In C, tuttavia, è difficile implementare un buon meccanismo standard generico per la gestione degli errori con tutte le funzionalità menzionate a causa della mancanza di eccezioni come parte del linguaggio di programmazione. Quindi la maggior parte dei programmi C ha i propri meccanismi di gestione degli errori con codici di ritorno, o "goto", o "salti lunghi", o una combinazione di questi. Queste sono spesso soluzioni pragmatiche che si adattano al particolare tipo di programma, ma non sono "abbastanza generiche" per adattarsi alla libreria C standard.


Ah, completamente dimenticato l'eredità C (dopo tutto il suo #include <cassert>). Adesso ha perfettamente senso.
Nessuno il

1
Non sono completamente d'accordo con questa intera risposta. Generare un'eccezione quando l'applicazione ha scoperto che il suo codice sorgente era difettoso è l'ultima risorsa in linguaggi come Java che non può fare di meglio, ma in C ++, sicuramente interrompere immediatamente il programma in una situazione del genere. Non si vuole pila svolgimento di causare eventuali ulteriori operazioni da eseguire in quel punto. Un programma difettoso può scrivere dati corrotti su file, database o socket di rete. Basta un arresto anomalo al più presto (e possibilmente riavviare il processo da un meccanismo esterno).
Christian Hackl,

1
@ChristianHackl: Sono d'accordo che ci sono situazioni in cui la chiusura di un programma è l'unica opzione praticabile, ma poi dovrebbe accadere anche in modalità di rilascio e uno assertstrumento anche sbagliato per questo (lanciare un'eccezione può anche essere la reazione sbagliata ). Tuttavia, sono abbastanza sicuro che in realtà sia assertstato usato anche per molti test in C, dove in C ++ oggi si userebbero eccezioni.
Doc Brown,

15

Se ti accorgi di voler abilitare gli asserti in una versione, hai chiesto agli asseriti di fare il lavoro sbagliato.

Il punto di forza è che non sono abilitati in una versione. Ciò consente di testare gli invarianti durante lo sviluppo con codice che altrimenti dovrebbe essere un codice di ponteggio. Codice che deve essere rimosso prima del rilascio.

Se hai qualcosa che ritieni debba essere testato anche durante il rilascio, scrivi il codice che lo verifica. IlIf throw costrutto funziona molto bene. Se desideri dire qualcosa di diverso rispetto agli altri, usa semplicemente un'eccezione descrittiva che dice ciò che desideri dire.

Non è che non puoi cambiare il modo in cui usi le asserzioni. È che farlo non ti dà nulla di utile, è contrario alle aspettative e non ti lascia in alcun modo pulito per fare ciò che le affermazioni dovevano fare. Aggiungi i test che sono inattivi in ​​una versione.

Non sto parlando di un'implementazione specifica dell'asserzione, ma del concetto di un'asserzione. Non voglio abusare di affermare o confondere i lettori. Volevo chiedere perché è così in primo luogo. Perché non ci sono ulteriori release_assert? Non ce n'è bisogno? Qual è la logica alla base dell'asserzione disabilitata in fase di rilascio? - Nessuno

Perché no relase_assert? Francamente perché le asserzioni non sono abbastanza buone per la produzione. Sì, c'è un bisogno, ma nulla soddisfa ciò che è necessario. Oh certo che puoi progettare il tuo. Meccanicamente il tuo tiro Se hai solo bisogno di un bool e di un'eccezione da lanciare. E questo potrebbe soddisfare le tue esigenze. Ma stai davvero limitando il design. Questo è il motivo per cui non mi sorprende che non ci sia un sistema di lancio delle eccezioni nella libreria delle lingue. Non è certo che non puoi farlo. Altri hanno . Ma affrontare il caso in cui le cose vanno male è l'80% del lavoro per la maggior parte dei programmi. E finora nessuno ci ha mostrato una buona taglia adatta a tutte le soluzioni. Gestire efficacemente questi casi può diventare complicato. Se avessimo avuto un sistema release_assert in scatola che non era all'altezza delle nostre esigenze, penso che avrebbe fatto più male che bene. Stai chiedendo una buona astrazione che significhi che non dovresti pensare a questo problema. Ne voglio uno anch'io ma non sembra che ci siamo ancora.

Perché gli asserti sono disabilitati in versione? Le affermazioni sono state create all'apice dell'età del codice delle impalcature. Il codice che abbiamo dovuto rimuovere perché sapeva che non lo volevamo in produzione, ma sapevamo che volevamo eseguire lo sviluppo per aiutarci a trovare i bug. Le asserzioni erano un'alternativa più chiara al if (DEBUG)modello che ci permetteva di lasciare il codice ma disabilitarlo. Ciò avveniva prima che i test unitari decollassero come il modo principale per separare il codice di test dal codice di produzione. Le asserzioni sono ancora utilizzate oggi, anche da esperti tester di unità, sia per chiarire le aspettative sia per coprire casi che continuano a fare meglio dei test unitari.

Perché non lasciare semplicemente il codice di debug in produzione? Perché il codice di produzione non deve mettere in imbarazzo la società, non formattare il disco rigido, non corrompere il database e non inviare e-mail minacciose al presidente. In breve, è bello poter scrivere il codice di debug in un posto sicuro dove non devi preoccuparti di questo.


2
Immagino che la mia domanda sia: perché questo codice deve essere rimosso prima del rilascio? I controlli non riducono molto le prestazioni e se falliscono c'è sicuramente un problema di cui preferirei un messaggio di errore più diretto. Quale vantaggio mi offre l'utilizzo di un'eccezione anziché di un'asserzione? Probabilmente non vorrei che il codice non correlato fosse in grado di catch(...)farlo.
Nessuno il

2
@Nobody Il più grande vantaggio di non usare assert per esigenze non assertive non è confondere i tuoi lettori. Se non si desidera disabilitare il codice, non usare modi di dire che segnalino che sarà. È negativo come usare if (DEBUG)per controllare qualcosa di diverso dal codice di debug. La micro ottimizzazione potrebbe non significare nulla nel tuo caso. Ma il linguaggio non dovrebbe essere sovvertito solo perché non ne hai bisogno.
candied_orange

Penso di non aver chiarito abbastanza bene le mie intenzioni. Non sto parlando di un'implementazione specifica assertma del concetto di un'asserzione. Non voglio abusare asserto confondere i lettori. Volevo chiedere perché è così in primo luogo. Perché non ce ne sono altri release_assert? Non ce n'è bisogno? Qual è la logica alla base dell'asserzione disabilitata in fase di rilascio?
Nessuno il

2
You're asking for a good abstraction.Non ne sono sicuro. Voglio principalmente affrontare problemi in cui non è possibile recuperare e che non dovrebbero mai accadere. Prendi questo insieme Because production code needs to [...] not format the hard drive [...]e direi che nei casi in cui gli invarianti sono rotti, prenderei un'asserzione in rilascio su UB in qualsiasi momento.
Nessuno il

1
@Nessuno "problemi in cui non è possibile recuperare" possono essere risolti generando eccezioni e non rilevandole. Puoi notare che non dovrebbero mai accadere nel testo del messaggio dell'eccezione.
candied_orange,

4

Le asserzioni sono uno strumento di debug , non una tecnica di programmazione difensiva. Se si desidera eseguire la convalida in tutte le circostanze, eseguire la convalida scrivendo un condizionale o creare la propria macro per ridurre la piastra di cottura.


4

assertè una forma di documentazione, come i commenti. Come i commenti, normalmente non li spediresti ai clienti - non appartengono al codice di rilascio.

Ma il problema con i commenti è che possono diventare obsoleti, eppure vengono lasciati entrare. Ecco perché le asserzioni sono buone - sono controllate in modalità debug. Quando l'assert diventa obsoleto, lo scopri rapidamente e saprai comunque come risolverlo. Quel commento che è diventato obsoleto 3 anni fa? Qualcuno immagina.


1
Quindi abortire su un invariante fallito prima che accada qualcosa non è un caso d'uso valido?
Nessuno

3

Se non vuoi che una "asserzione" sia disattivata, sentiti libero di scrivere una semplice funzione che abbia un effetto simile:

void fail_if(bool b) {if(!b) std::abort();}

Cioè, assertè per le prove in cui si fare desidera loro di andare via nel prodotto spedito. Se vuoi che quel test faccia parte del comportamento definito del programma, assertè lo strumento sbagliato.


1
Ne sono consapevole. La domanda è più in linea con il motivo per cui il default è così com'è.
Nessuno il

3

È inutile discutere cosa dovrebbe fare l'asserzione, fa quello che fa. Se vuoi qualcosa di diverso, scrivi la tua funzione. Ad esempio, ho Assert che si interrompe nel debugger o non fa nulla, ho AssertFatal che arresta in modo anomalo l'app, ho funzioni booler Asserted e AssertionFailed che affermano e restituiscono il risultato in modo da poter affermare e gestire la situazione.

Per qualsiasi problema imprevisto devi decidere qual è il modo migliore per gestirlo sia da parte dello sviluppatore che dell'utente.


Non era mia intenzione discutere di ciò che l'affermazione dovrebbe fare. La mia motivazione per questa domanda è stata quella di trovare il ragionamento alla base degli asseriti di non essere nella build di rilascio perché sto per scrivere il mio e voglio raccogliere informazioni su casi d'uso, aspettative e trappole.
Nessuno il

Hm, non verify(cond)sarebbe il modo normale di affermare e restituire il risultato?
Deduplicatore

1
Sto scrivendo un codice in Ruby, non in C, ma non sono d'accordo con la maggior parte delle risposte di cui sopra, poiché interrompere il programma con la stampa di un backtrace funziona bene per me come tecnica di programmazione difensiva ....... il mio commento non si adattava al dimensione massima del commento in caratteri, quindi ho scritto un'altra risposta di seguito.
Nakilon,

2

Come altri hanno sottolineato, assertè una specie del tuo ultimo bastione di difesa contro errori del programmatore che non dovrebbe mai accadere. Si tratta di controlli di sanità mentale che si spera che non manchino a destra ea sinistra al momento della spedizione.

È inoltre progettato per essere omesso da build di versioni stabili, per qualsiasi motivo gli sviluppatori possano trovare utili: estetica, prestazioni, qualunque cosa vogliano. Fa parte di ciò che separa una build di debug da una build di rilascio e per definizione una build di rilascio è priva di tali asserzioni. Quindi c'è una sovversione del progetto se si desidera rilasciare la "build di rilascio analogica con asserzioni in atto" che sarebbe un tentativo di una build di rilascio con una _DEBUGdefinizione del preprocessore e non NDEBUGdefinita; non è più una build di rilascio.

Il design si estende anche nella libreria standard. Come esempio di base tra numerosi, molte implementazioni di std::vector::operator[]volontà saranno assertun controllo di integrità per assicurarsi che non si stia verificando il vettore fuori dai limiti. E la libreria standard inizierà a funzionare molto, molto peggio se si abilitano tali controlli in una build di rilascio. Un punto di riferimento vectordell'utilizzooperator[]e un ctor di riempimento con tali asserzioni incluse contro un semplice array dinamico vecchio mostrerà spesso che l'array dinamico è considerevolmente più veloce fino a quando non disabiliti tali controlli, quindi spesso influiscono sulle prestazioni in modi lontani, tutt'altro che banali. Un controllo puntatore nullo qui e un controllo fuori limite lì possono effettivamente diventare una spesa enorme se tali controlli vengono applicati milioni di volte su ogni frame in loop critici che precedono il codice semplice come il dereferenziamento di un puntatore intelligente o l'accesso a un array.

Quindi probabilmente stai desiderando uno strumento diverso per il lavoro e uno che non è progettato per essere omesso dai build di rilascio se vuoi build di rilascio che eseguono tali controlli di integrità in aree chiave. Il più utile che trovo personalmente è la registrazione. In tal caso, quando un utente segnala un bug, le cose diventano molto più semplici se allegano un registro e l'ultima riga del registro mi dà un indizio grande su dove si è verificato il bug e su quale potrebbe essere. Quindi, riproducendo i loro passi in una build di debug, potrei anche ottenere un errore di asserzione, e quel fallimento di asserzione mi dà ulteriori indizi per semplificare il mio tempo. Tuttavia, poiché la registrazione è relativamente costosa, non la utilizzo per applicare controlli di integrità di livello estremamente basso, come assicurarsi che a una matrice non sia possibile accedere senza limiti in una struttura di dati generica.

Eppure alla fine, e un po 'd'accordo con te, ho potuto vedere un caso ragionevole in cui potresti voler consegnare ai tester qualcosa che assomiglia a una build di debug durante i test alfa, ad esempio con un piccolo gruppo di tester alfa che, diciamo, hanno firmato un accordo di non divulgazione . Lì potrebbe semplificare il test alfa se dai ai tuoi tester qualcosa di diverso da una build a rilascio completo con alcune informazioni di debug allegate insieme ad alcune funzionalità di debug / sviluppo come test che possono eseguire e output più dettagliato mentre eseguono il software. Ho visto almeno alcune grandi società di giochi fare cose del genere per Alpha. Ma è per qualcosa come alfa o test interni in cui stai davvero cercando di dare ai tester qualcosa di diverso da una build di rilascio. Se stai effettivamente cercando di distribuire una build di rilascio, quindi per definizione, non dovrebbe avere_DEBUG definito altrimenti confonde davvero la differenza tra una build "debug" e "release".

Perché questo codice deve essere rimosso prima del rilascio? I controlli non riducono molto le prestazioni e se falliscono c'è sicuramente un problema di cui preferirei un messaggio di errore più diretto.

Come indicato sopra, i controlli non sono necessariamente banali dal punto di vista delle prestazioni. Molti sono probabilmente banali ma, di nuovo, anche la lib standard li usa e potrebbe influire sulle prestazioni in modi inaccettabili per molte persone in molti casi se, diciamo, l'attraversamento ad accesso casuale std::vectorrichiedesse 4 volte di più in quella che dovrebbe essere una build di rilascio ottimizzata a causa del controllo dei suoi limiti che non dovrebbe mai fallire.

In un ex team dovevamo effettivamente fare in modo che la nostra libreria di matrici e vettori escludesse alcuni asserzioni in alcuni percorsi critici solo per rendere più veloci le build di debug, perché quegli asserzioni rallentavano le operazioni matematiche di un ordine di grandezza fino al punto in cui si trovava iniziando a chiederci di aspettare 15 minuti prima che potessimo anche risalire al codice di interesse. I miei colleghi in realtà volevano solo rimuovere il fileassertsperché hanno scoperto che il solo fatto di fare una differenza enorme. Invece, abbiamo deciso di evitare che i percorsi di debug critici li evitassero. Quando abbiamo fatto in modo che quei percorsi critici usassero direttamente i dati vettore / matrice senza passare attraverso il controllo dei limiti, il tempo richiesto per eseguire l'operazione completa (che includeva più della semplice matematica vettoriale / matrice) si riduceva da minuti a secondi. Quindi questo è un caso estremo ma sicuramente le affermazioni non sono sempre trascurabili dal punto di vista delle prestazioni, nemmeno vicine.

Ma è anche il modo in cui assertssono progettati. Se non avessero avuto un così grande impatto sulle prestazioni su tutta la linea, allora potrei favorirlo se fossero progettati come qualcosa di più di una funzione di build di debug o potremmo usare vector::atche include i limiti che controllano anche nelle build di rilascio e si lancia fuori dai limiti accesso, ad es. (ma con un enorme successo di prestazioni) Ma attualmente trovo il loro design molto più utile, dato il loro enorme impatto sulle prestazioni nei miei casi, come una funzione di solo debug che viene omessa quando NDEBUGdefinita. Almeno per i casi con cui ho lavorato, fa una grande differenza per una build di rilascio escludere i controlli di integrità che non dovrebbero mai fallire in primo luogo.

vector::at vs. vector::operator[]

Penso che la distinzione di questi due metodi sia al centro di questo e dell'alternativa: le eccezioni. vector::operator[]implementazioni in genere assertper assicurarsi che l'accesso fuori dai limiti inneschi un errore facilmente riproducibile quando si tenta di accedere a un vettore fuori limite. Ma gli implementatori della libreria lo fanno supponendo che non costerà un centesimo in una build di rilascio ottimizzata.

Nel frattempo vector::atviene fornito che esegue sempre il controllo dei limiti e genera anche nelle build di rilascio, ma ha una penalità di prestazione al punto in cui vedo spesso molto più codice che usare vector::operator[]rispetto a vector::at. Gran parte del design del C ++ fa eco all'idea di "pagare per quello che usi / hai bisogno", e molte persone spesso favoriscono operator[], il che non si preoccupa nemmeno dei limiti che controllano nelle build di rilascio, in base all'idea che non indossano non è necessario che i limiti vengano controllati nelle build di rilascio ottimizzate. Improvvisamente se le affermazioni fossero abilitate nelle build di rilascio, le prestazioni di questi due sarebbero identiche e l'uso del vettore finirebbe sempre per essere più lento di un array dinamico. Quindi una parte enorme del design e dei vantaggi delle asserzioni si basa sull'idea che queste diventano libere in una build di rilascio.

release_assert

Questo è interessante dopo aver scoperto queste intenzioni. Naturalmente i casi d'uso di ognuno sarebbero diversi, ma penso che troverei un uso per uno release_assertche fa il controllo e bloccherà il software mostrando un numero di riga e un messaggio di errore anche nelle build di rilascio.

Sarebbe per alcuni casi oscuri nel mio caso in cui non voglio che il software si ripristini con grazia come farebbe se viene generata un'eccezione. Vorrei che si arrestasse in modo anomalo anche in rilascio in quei casi in modo che all'utente potesse essere assegnato un numero di riga per segnalare quando il software ha riscontrato qualcosa che non dovrebbe mai accadere, ancora nel regno dei controlli di integrità per errori del programmatore, non errori di input esterni come eccezioni, ma abbastanza economico da fare senza preoccuparsi del suo costo di rilascio.

In realtà ci sono alcuni casi in cui troverei un arresto anomalo con un numero di riga e un messaggio di errore preferibile al recupero con grazia da un'eccezione generata che potrebbe essere abbastanza economica da mantenere in una versione. E ci sono alcuni casi in cui è impossibile recuperare da un'eccezione, come un errore riscontrato nel tentativo di recuperare da uno esistente. Lì troverei una misura perfetta per un release_assert(!"This should never, ever happen! The software failed to fail!");e naturalmente sarebbe sporco a buon mercato poiché il controllo sarebbe eseguito all'interno di un percorso eccezionale in primo luogo e non costerebbe nulla nei normali percorsi di esecuzione.


La mia intenzione non era quella di abilitare assert nel codice di terze parti, vedere la modifica chiarificatrice. La citazione dal mio commento omette il contesto dalla mia domanda: Additionally, the performance argument for me only counts when it is a measurable problem.Quindi l'idea è di decidere caso per caso quando prendere un'asserzione dalla versione.
Nessuno il

Uno dei problemi con l'ultimo commento è che la libreria standard usa lo stesso assertche si basa sugli stessi _DEBUG/NDEBUGvalori predefiniti del preprocessore di quello che useresti quando usi la assertmacro. Quindi non c'è modo di abilitare selettivamente le asserzioni solo per un pezzo di codice senza abilitarlo anche per la lib standard, ad esempio, supponendo che usi la lib standard.

Esiste un controllo iteratore STL che è possibile disabilitare separatamente che disabilita alcune delle asserzioni, ma non tutte.

È fondamentalmente uno strumento approssimativo, non granulare, e sempre con quell'intento progettuale di essere disabilitato nella versione, quindi i tuoi compagni di squadra potrebbero usarlo in aree critiche contro il presupposto che non influenzerà le prestazioni della versione, la libreria standard lo usa che in aree critiche, altre librerie di terze parti lo usano in questo modo, ecc. E quando vuoi qualcosa puoi disabilitare / abilitare più specificamente un pezzo di codice e non l'altro, torniamo a guardare qualcosa di diverso assert.

vector::operator[]e vector::at, per esempio, avrebbe praticamente le stesse prestazioni se le asserzioni fossero abilitate nelle build di rilascio, e non avrebbe più senso operator[]usarle dal punto di vista delle prestazioni poiché farebbe comunque il controllo dei limiti.

2

Sto codificando in Ruby, non in C / C ++, quindi non parlerò della differenza tra asserzioni ed eccezioni, ma vorrei parlarne come una cosa che interrompe il runtime . Non sono d'accordo con la maggior parte delle risposte di cui sopra, poiché interrompere il programma con la stampa di un backtrace funziona bene per me come tecnica di programmazione difensiva.
Se esiste un modo per asserire la routine (assolutamente non importa come sia sintatticamente scritto e se la parola "assert" è usata o esiste nel linguaggio di programmazione o dsl) da chiamare, ciò significa che un po 'di lavoro dovrebbe essere fatto e il prodotto passa immediatamente da "rilasciato, pronto per l'uso" a "necessita patch" - ora riscrivilo nella gestione delle eccezioni reali o correggi un bug che causava la visualizzazione di dati errati.

Voglio dire che Assert non è una cosa con cui dovresti convivere e chiamare frequentemente - è un segnale di arresto che indica che dovresti fare smth per evitare che accada mai più. E dire che "build di rilascio non dovrebbe avere asserzioni" è come dire "build di rilascio non dovrebbe avere bug" - amico, è quasi impossibile, affrontarlo.
Oppure pensali come "errori di unittest realizzati ed eseguiti dall'utente finale". Non puoi prevedere tutte le cose che l'utente farà con il tuo programma ma se smth troppo grave va storto, dovrebbe fermarsi - è simile a come costruisci pipeline di costruzione - interrompi il processo e non pubblichi, vero? ? L'asserzione impone all'utente di interrompere, segnalare e attendere il tuo aiuto.

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.