Metodo più bella:
#ifdef _DEBUG
#define DBOUT cout // or any other ostream
#else
#define DBOUT 0 && cout
#endif
DBOUT << "This is a debug build." << endl;
DBOUT << "Some result: " << doSomething() << endl;
Finché non fai niente di strano, funzioni chiamate e passati a DBOUT
non saranno chiamati in build di rilascio. Questa macro funziona a causa della precedenza degli operatori e della logica AND; poiché &&
ha precedenza inferiore rispetto a <<
, le build di rilascio compilano DBOUT << "a"
come 0 && (cout << "a")
. L'AND logico non valuta l'espressione a destra se l'espressione a sinistra viene valutata a zero o false
; poiché l'espressione mano sinistra viene sempre valutata a zero, l'espressione della mano destra viene sempre rimossa da qualsiasi compilatore che valga la pena di utilizzare, tranne quando l'ottimizzazione è disabilitata (e anche in questo caso, il codice ovviamente non raggiungibile può ancora essere ignorato.)
Ecco un esempio di cose strane che si romperà questa macro:
DBOUT << "This is a debug build." << endl, doSomething();
Guarda le virgole. doSomething()
verrà sempre chiamato, indipendentemente dal fatto che sia definito o meno _DEBUG
. Questo è perché l'istruzione è valutata in build di rilascio come:
(0 && (cout << "This is a debug build." << endl)), doSomething();
// evaluates further to:
false, doSomething();
Per utilizzare virgole con questa macro, la virgola devono essere confezionate in parentesi, così:
DBOUT << "Value of b: " << (a, b) << endl;
altro esempio:
(DBOUT << "Hello, ") << "World" << endl; // Compiler error on release build
In build di rilascio, questo è valutato come:
(0 && (cout << "Hello, ")) << "World" << endl;
// evaluates further to:
false << "World" << endl;
che causa un errore del compilatore perché bool
non può essere spostato a sinistra da un puntatore char
a meno che non sia definito un operatore personalizzato. Questa sintassi provoca anche problemi aggiuntivi:
(DBOUT << "Result: ") << doSomething() << endl;
// evaluates to:
false << doSomething() << endl;
Proprio come quando la virgola è stata usata male, doSomething()
ancora viene chiamato, perché il suo risultato deve essere passato al gestore sinistra-shift. (Ciò può verificarsi solo quando un operatore personalizzato è definito che sinistra-sposta un bool
da un puntatore char
;. In caso contrario, si verifica un errore di compilazione)
Non parenthesize DBOUT << ...
. Se si desidera confrontare un intero intero letterale in parentesi, quindi parentesi, ma non sono a conoscenza di un singolo motivo valido per la parentesi di un operatore di flusso.
Grazie! Stavo iniziando a pensare qualcosa in questo senso e sono felice di vedere che non sono l'unico a pensarlo. Lo proverò lunedì al lavoro e vedrò quanto bene il compilatore è in grado di ottimizzare il flusso. – Emanuel
Chiunque utilizzi questo metodo presta attenzione al fatto che alcuni elementi non verranno ottimizzati in modalità di rilascio. Se hai: '' 'debug << someCPUIntensiveFunctionOrFunctionWhichMayAffectState() <<" \ n "' '' verrà ancora eseguito in modalità di rilascio. Ho perso questo cavetto la prima volta. –