2017-09-11 2 views
4

Kontext: In diesem answer erfuhr ich, dass gcc __builtin_unreachable() einige überraschend impactful Auswirkungen auf die Leistung haben kann, wie es, dass die folgende scheint:Gibt es einen Grund dafür, assert() nicht in ein Makro zu packen, das in gcc zu __builtin_unreachable() aufgelöst wird?

if(condition) __builtin_unreachable(); 

vollständig abgezogen wird, und als Optimierungshinweis solange condition verwendet kann garantiert keine Nebenwirkung haben.

So meine erste Reaktion darauf ist, dass ich das folgende Makro erstellen sollte, und verwenden Sie es absolut überall würde ich normalerweise assert() verwenden, da Nebeneffekt induziert Code innerhalb einer assert() ein großer Fehler in erster Linie sein würde:

// TODO: add handling of other compilers as appropriate. 
#if defined(__GNUC__) && defined(NDEBUG) 
    #define my_assert(condition) \ 
    if(!(condition)) __builtin_unreachable() 
#else 
    #define my_assert(condition) assert(condition) 
#endif 

aus Standards Perspektive, würde dies eine Spaltung in der Funktionalität zwischen normalen erstellen und NDEBUG baut, mit dem Sie ein Argument dieses Makro schließt davon, dass das Standardverhalten von assert() machen könnte. Da mein Code jedoch im Fall von Assertionsfehlern funktionell tot im Wasser ist, ist er vom Verhalten her gesehen völlig äquivalent.

Also meine Frage ist: Kann jemand einen Grund denken, dies nicht zu tun (appart aus behauptet, dass viele Umleitungen beinhalten)?

Bevor Sie fragen, ja, habe ich überprüft, dass gcc Verhalten ist, um die Behauptung weg in NDEBUG Builds void.

+0

Relevante https://stackoverflow.com/a/40447259/817643 – StoryTeller

+0

Kein Grund, dies nicht zu tun, soweit ich das beurteilen kann. Sie nehmen etwas für die Optimierung in Release-Builds an und ersetzen es durch eine Assertion in Debug-Builds, um Programmierfehler zu erfassen. – StoryTeller

+1

"Verwenden Sie es absolut überall" -Ansatz wird nicht wirklich funktionieren, weil Debug-Assertionen oft Variablen und Aufrufe enthalten, die nur im Debug-Modus verfügbar sind. Die bessere Idee wäre, ein dediziertes Makro mit einem passenderen Namen wie 'my_assume' zu ​​definieren und es nur an geeigneten Stellen zu verwenden. – VTT

Antwort

2

Ja, es gibt einen Grund, es nicht zu benutzen. Einige Leute die folgende defensive Code Praxis verwenden, die assert und Ausnahme kombiniert (assert(x>0); if (!(x<0)) throw std::logic_error("..")) - siehe diese Antwort:

Test Cases AND assertion statements

Ihr Makro bricht lautlos die Ausnahme-Teil für Release-Builds.

+2

Ich mag diese Praxis wirklich nicht, da sie Programmierfehler und Laufzeitfehler zusammenführt. Diese Behauptung hat meiner Meinung nach nichts zu tun. Meine Codebasis würde darunter nicht leiden, aber das ist eine gute Sache, die man im Kopf behalten sollte. – Frank

+2

Ich sehe den Wert in diesem tbh nicht. Es scheint den Zweck von 'assert()' zu besiegen, da es keine Auswirkungen auf den Release-Code hat.Nutzen Sie auch die Ausnahme, wenn Sie das möchten. – Galik

+1

Dies ist kein defensiver, sondern redundanter Code. Wenn Sie in Release-Builds Überprüfungen vornehmen müssen, erstellen Sie entweder einen speziellen, kompilierten-sogar-in-release-Modus release_assert, oder verwenden Sie nur das Exception-Werfen. Assert + Throw ist eine schlechte Übung. – geza

Verwandte Themen