Domanda

Con questo intendo dire: cosa devo fare per avere asserzioni utili nel mio codice?

MFC è abbastanza semplice, utilizzo solo ASSERT(qualcosa).

Qual è il modo non MFC?

Modificare: È possibile interrompere l'asserzione in assert.c anziché nel mio file che chiamava assert()?

Modificare: Qual è la differenza tra <assert.h> & <cassert>?

Risposta accettata: Un sacco di ottime risposte in questo post, vorrei poter accettare più di una risposta (o qualcuno le unirebbe tutte).Quindi la risposta viene assegnata a Ferruccio (per la prima risposta).

È stato utile?

Soluzione

#include <cassert>

assert(something);

e per il controllo in fase di compilazione, le affermazioni statiche di Boost sono piuttosto utili:

#include <boost/static_assert.hpp>

BOOST_STATIC_ASSERT(sizeof(int) == 4);  // compile fails if ints aren't 32-bit

Altri suggerimenti

Dipende dal fatto che tu stia cercando qualcosa che funzioni al di fuori di Visual C ++. Dipende anche dal tipo di affermazione che stai cercando.

Esistono alcuni tipi di affermazioni:

  1. preprocessore
    Queste affermazioni sono fatte usando la direttiva preprocessore #error
    Le asserzioni del preprocessore vengono valutate solo durante la fase di preelaborazione e quindi non sono utili per elementi come i modelli.

  2. Tempo di esecuzione
    Queste affermazioni sono fatte usando la funzione assert() definita in <cassert>
    Le asserzioni relative al tempo di esecuzione vengono valutate solo in fase di esecuzione. E come sottolineato da BoltBait, non vengono compilati se la NDEBUG macro è stata definita.

  3. Static
    Queste affermazioni vengono fatte, come hai detto, utilizzando la macro ASSERT(), ma solo se si utilizza MFC. Non conosco un altro modo di fare asserzioni statiche che fa parte dello standard C / C ++, tuttavia, la libreria Boost offre un'altra soluzione: static_assert.
    La funzione <=> della libreria Boost è qualcosa che verrà aggiunta nel C ++ 0x standard .

Come ulteriore avvertimento, la funzione <=> suggerita da Ferruccio non ha lo stesso comportamento della macro MFC <=>. Il primo è un'asserzione del tempo di esecuzione, mentre il secondo è un'asserzione statica.

Spero che questo aiuti!

Assert è (di solito) Solo debug

Il problema con "assert" è che di solito si trova nei binari di debug e che alcuni sviluppatori li usano come se il codice fosse ancora in produzione.

Questo non è un male di per sé, poiché il codice dovrebbe essere testato intensamente e, quindi, i bug che producono l'asserzione verranno sicuramente scoperti e rimossi.

Ma a volte (la maggior parte delle volte?), i test non sono così intensivi come avremmo voluto.Non parlerò di un vecchio lavoro in cui dovevamo programmare fino all'ultimo minuto (non chiedere...A volte i manager sono semplicemente...Ehm...)...Qual è lo scopo di un'asserzione che aggiungi a un codice che verrà compilato e consegnato come file binario di rilascio al cliente il minuto successivo?

Asserire in (alcune) applicazioni della vita reale

Nel nostro team avevamo bisogno di qualcosa per rilevare l’errore e allo stesso tempo di qualcos’altro per gestirlo.E ne avevamo bisogno, potenzialmente, su Release Build.

Assert rileverà e gestirà l'errore solo nella build di debug.

Quindi abbiamo aggiunto invece una macro XXX_ASSERT e una macro XXX_RAISE_ERROR.

La macro XXX_ASSERT farebbe la stessa cosa della macro ASSERT, ma verrebbe creata sia in Debug che in Release.Il suo comportamento (scrivere un registro, aprire una finestra di messaggio, non fare nulla, ecc.) potrebbe essere controllato da un file .INI e POI interrompere/uscire dall'applicazione.

Questo è stato utilizzato come:

bool doSomething(MyObject * p)
{
   // If p is NULL, then the app will abort/exit
   XXX_ASSERT((p != NULL), "Hey ! p is NULL !") ;

   // etc.
}

La macro XXX_RAISE_ERROR "registrerebbe" solo l'errore ma non proverebbe a gestirlo.Ciò significa che potrebbe registrare il messaggio in un file e/o aprire un MessageBox con il messaggio e un pulsante per continuare e un altro per avviare una sessione di debug (come da configurazione del file .INI).Questo è stato utilizzato come:

bool doSomething(MyObject * p)
{
   if(p == NULL)
   {
      // First, XXX_RAISE_ERROR will alert the user as configured in the INI file
      // perhaps even offering to open a debug session
      XXX_RAISE_ERROR("Hey ! p is NULL !") ;
      // here, you can handle the error as you wish
      // Than means allocating p, or throwing an exception, or
      // returning false, etc.
      // Whereas the XXX_ASSERT could simply crash.
   }

   // etc.
}

Un anno dopo la loro introduzione nelle nostre librerie, viene utilizzato solo XXX_RAISE_ERROR.Ovviamente non può essere utilizzato su parti dell'app in cui il tempo è critico (abbiamo un XXX_RAISE_ERROR_DBG per questo), ma ovunque va bene.E il fatto che si possa utilizzare qualunque gestione degli errori preferita e che possa essere attivata a piacimento, sia sul computer dello sviluppatore, sia sul tester, o anche sull'utente, è piuttosto utile.

Per rispondere alla domanda nel tuo secondo " modifica " ;:

lt &; & Assert.h gt; è l'intestazione C

lt &; cassert gt &; è l'intestazione della libreria standard C ++ ... in genere include < assert.h gt &;

Per interrompere il file che ha chiamato l'asserzione, puoi utilizzare una macro personalizzata che genera un'eccezione o chiama __debugbreak:

#define MYASSERT(EXPR, MSG) if (!(EXPR)) throw MSG;

o

#define MYASSERT(EXPR) if (!(EXPR)) __debugbreak();

Utilizzo dell'assert di base

#include <cassert>

/* Some code later */
assert( true );

Note sulle migliori pratiche

Gli asserti sono usati per identificare stati di runtime che dovrebbero essere veri . Di conseguenza, vengono compilati in modalità di rilascio.

Se hai una situazione in cui vuoi che un'asserzione colpisca sempre, puoi passarci il falso. Ad esempio:

switch ( someVal ):
{
case 0:
case 1:
  break;
default:
  assert( false ); /* should never happen */
}

È anche possibile trasmettere un messaggio attraverso assert:

assert( !"This assert will always hit." );

Le basi di codice mature estendono frequentemente la funzionalità di asserzione. Alcune delle estensioni comuni includono:

  • Attivare / disattivare le asserzioni per modulo per localizzare i test.
  • Creazione di una macro assert aggiuntiva che viene compilata nella maggior parte dei build di debug. Ciò è auspicabile per il codice che viene chiamato molto frequentemente (milioni di volte al secondo) ed è improbabile che sia errato.
  • Consentire agli utenti di disabilitare l'asserzione attualmente colpita, tutte le asserzioni nell'unità di compilazione o tutte le asserzioni nella base di codice. Questo impedisce l'attivazione di affermazioni benigne, creando build inutilizzabili.

Dichiarazioni CRT specifiche di Microsoft

#include <crtdbg.h>
#include <sstream>
...
// displays nondescript message box when x <= 42
_ASSERT(x > 42);
// displays message box with "x > 42" message when x <= 42
_ASSERTE(x > 42);
// displays message box with computed message "x is ...!" when x <= 42
_ASSERT_EXPR(
   x > 42, (std::stringstream() << L"x is " << x << L"!").str().c_str());

Esiste una libreria open source più avanzata chiamata ModAssert, che ha asserzioni che funzionano sia su Visual C ++ che su gcc. Probabilmente anche su altri compilatori, non lo so per certo. Ci vuole del tempo per impararlo, ma se vuoi delle buone asserzioni che non dipendono dall'MFC, guarda queste. È all'indirizzo http://sourceforge.net/projects/modassert/

usa intellisense per aprirlo in Visual Studio (tasto destro)

// cassert standard header
#include <yvals.h>
#include <assert.h>

yvals.h è roba di windows. quindi, per quanto riguarda assert () stesso, i due modi per includerlo sono identici. è buona norma usare <cxxx> perché spesso non è così semplice (avvolgimento dello spazio dei nomi e forse altra magia)

Questo si interrompe sul sito del chiamante per me ...

ecco un articolo che spiega perché non vuoi scrivere tu stesso questa macro.

Ecco la mia più recente iterazione di una funzione di asserzione in C ++: http://pempek.net/articles/2013/11/17/cross-platform-cpp-assertion-library/

È un lib drop-in di 2 file che puoi facilmente aggiungere al tuo progetto.

Per rispondere alla terza domanda del richiedente: il primo motivo per cui utilizziamo " cassert " invece di " assert.h " è perché, nel caso di C ++, è stata concessa la possibilità che il compilatore C ++ non memorizzi le descrizioni delle funzioni in file di codice, ma in una dll o nel compilatore stesso. Il secondo è che potrebbero essere apportate lievi modifiche alle funzioni al fine di facilitare le differenze tra C e C ++, presenti o future. Poiché assert.h è una libreria C, la preferenza è usare & Quot; cassert & Quot; mentre in C ++.

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top