eigenes assert



  • hallo, ich brächte eine eigene version von assert

    1. weil assert mir nicht flexible genug ist
    2. weil es mir um eher sanfte asserts geht

    ich dachte an folgende implementierung :

    template <bool>
    eigenes_assert(bool bedingung, ...);
    
    template<>
    eigenes_assert<false>(bool bedingung, ...)
    {}
    
    template<>
    eigenes_assert<true>(bool bedingung, ...)
    {
    do_something();
    }
    
    static const bool assert_enabled = false;
    eigenes_assert<assert_enabled>(inVec.size() == outVec.size(),... );
    

    zerfallen diese funktionsaufrufe bei "false" auch zu nichts, wie beim richtigen assert?

    danke Treb



  • Treb schrieb:

    zerfallen diese funktionsaufrufe bei "false" auch zu nichts, wie beim richtigen assert?

    das richtige assert 'zerfällt' in der release-version zu nichts. in der debug-version ist es vorhanden.
    🙂



  • ja, ist das bei meiner version für

    assert_enabled = false;
    

    auch so? Oder erzeuge ich damit asm-code? Dann würde ich mich nämlich eher
    mit dem "richtigen" assert begnügen, als mehr laufzeit zu erzeugen



  • ich denke mal, ein durchschnittlicher compiler sollte es rausschmeissen, wenn assert_enabled==false. wahrscheinlich brauchst du dafür noch nicht mal templates.
    eine andere möglichkeit wäre, mit dem preprozessor zu arbeiten (#ifdef). dann kannst du dir 100%ig sicher sein, dass nichts mehr vorhanden ist, wenn du's nicht willst
    🙂



  • Der Unterschied ist eher grundsätzlich: Das normale assert prüft die Bedingung zur Laufzeit, Dein eigenes_assert prüft die Bedingung bereits zur Compilezeit, d.h. sie muss konstant sein. do_something wird zur Laufzeit ausgeführt, wenn die Bedingung zur Compilezeit true war (ist das btw. was Du willst?).

    Allerdings kann man davon ausgehen, dass der Compiler - wenn die Definition von eigenes_assert<false> sichtbar ist - den Funktionsaufruf bei so einer trivialen, weil leeren, Funktion inlined und für diese Zeile keinen Code erzeugt.



  • LordJaxom schrieb:

    Der Unterschied ist eher grundsätzlich: Das normale assert prüft die Bedingung zur Laufzeit, Dein eigenes_assert prüft die Bedingung bereits zur Compilezeit, d.h. sie muss konstant sein. do_something wird zur Laufzeit ausgeführt, wenn die Bedingung zur Compilezeit true war (ist das btw. was Du willst?).

    Ne, schau Dir den Code nochmal genauer an. Der Template-Parameter ist nur dazu da, die Assertions an- bzw. auszuschalten. Die Bedingung ist der nachfolgende Parameter.


  • Mod

    Die Auswertung der Funktionsargumente findet immer statt, nicht so bei assert.



  • Konrad Rudolph schrieb:

    Ne, schau Dir den Code nochmal genauer an. Der Template-Parameter ist nur dazu da, die Assertions an- bzw. auszuschalten. Die Bedingung ist der nachfolgende Parameter.

    Ups, stimmt natürlich auffallend.



  • und da du eh makros nehmen wirst, kannste jetzt sogar im assert-fall vor dem werfen der exception ein __asm int 3; reinfummeln. das ist super-angenehm, wenn der debugger an dieser stelle anhält und du die variablen in der IDE inspizieren kannst.

    es folgt der erstebeste code, den ich dazu fand:

    #ifndef DEBUG_H
    #define DEBUG_H
    #pragma once
    
    void traceException(char const* file,int line,Exception const& exc);//loggt sie z.B. in ein file
    inline void doNothing(){};//zum semikolon-abfackeln
    bool isDebuggerPresent();//in der winapi
    
    //ein breakpoint im code
    #define DBREAK() if(isDebuggerPresent()){__asm int 3}else doNothing()
    
    //returnTrue() macht ne warnung weg
    #define DTHROW(exc) if(returnTrue()){traceException(__FILE__,__LINE__,exc);DBREAK();throw exc;}else doNothing()
    
    #ifndef NDEBUG
    #define ASSERTE(cond,exc) if(!bool(cond))DTHROW(exc);else doNothing()
    #else
    #define ASSERTE(cond,exc)
    #endif
    
    #endif
    

    bei MSVC ist

    #else
    #define ASSERTE(cond,exc) _assume(cond)
    #endif
    

    immer eine überlegung wert.



  • Statt "doNothing" nimmt man normalerweise sowas wie "((void)0)", und assert() sollte IMO nicht "leer" definiert werden, sonst bekommt man mit bestimmtem Code Probleme.
    Auch sollte assert IMO an möglichst allen Stellen gehen wo eine void-Funktion geht, also z.B. auch in solchen Konstrukten:

    z.B. sowas:

    void foo(int x)
    {
        assert(x < 100), printf("%d", x);
        int y = (assert(x != 0), 100/x);
    }
    

    (Der Code ist natürlich grausam, und soll nur zeigen wo ein über "if" implementiertes "assert" Probleme bereiten könnte.)

    Das lässt sich z.B. erreichen indem man assert() über && oder || definiert, so wie es in den MSVC Headern gemacht wird:

    #define assert(_Expression) (void)( (!!(_Expression)) || (_wassert(_CRT_WIDE(#_Expression), _CRT_WIDE(__FILE__), __LINE__), 0) )
    


  • hustbaer schrieb:

    Sund assert() sollte IMO nicht "leer" definiert werden, sonst bekommt man mit bestimmtem Code Probleme.

    jup. fehler von mir.

    hustbaer schrieb:

    Auch sollte assert IMO an möglichst allen Stellen gehen wo eine void-Funktion geht, also z.B. auch in solchen Konstrukten:
    ...

    kriege ich dann auch hin, dass __asm int 3; ohne funktionsaufruf klappt? glaube nicht. der funktionsaufruf wäre grausam, der debugger wäre immer innerhalb der funktion statt auf der fehlerzeile.



  • volkard schrieb:

    hustbaer schrieb:

    Auch sollte assert IMO an möglichst allen Stellen gehen wo eine void-Funktion geht, also z.B. auch in solchen Konstrukten:
    ...

    kriege ich dann auch hin, dass __asm int 3; ohne funktionsaufruf klappt? glaube nicht. der funktionsaufruf wäre grausam, der debugger wäre immer innerhalb der funktion statt auf der fehlerzeile.

    Keine Ahnung, ist für mich aber kein Ding. Mich persönlich stört es nicht wenn ein assert() irgendwo Triggert wo noch ein oder zwei Funktionen zusätzlich auf dem Call-Stack sind. Man sieht ja trotzdem recht schnell wohers eigentlich kommt, gerade dazu ist das Call-Stack ja gut 🙂



  • hustbaer schrieb:

    Keine Ahnung, ist für mich aber kein Ding. Mich persönlich stört es nicht wenn ein assert() irgendwo Triggert wo noch ein oder zwei Funktionen zusätzlich auf dem Call-Stack sind. Man sieht ja trotzdem recht schnell wohers eigentlich kommt, gerade dazu ist das Call-Stack ja gut 🙂

    Mich hingegen stört es tierisch. Der neue VC++-Compiler (bzw. die neue STL) schickt einen bei einem Laufzeitfehler erst mal ins Nirvana, aus dem man sich dann hervorkämpfen muss. Finde ich nicht gut.


Log in to reply