[Suchen Autor für:] Bugs bei denen man lange sitzt



  • Wie wäre es mit einem Artikel bezüglich eher ungewöhnlichen Bugs bei denen man lange sitzt ehe man sie gefunden hat. Also so eine Art Auflistung.

    Ich hätte vier Kandidaten:

    • Selbstinitialisierung
    class Car{
    public:
      Car(const std::string&brant_name):
        brand_name(brand_name){}
    private:
      std::string brand_name;
    };
    
    • Parameter deckt Member
    class Car{
    public:
      Car(std::string brand_name):
        brand_name("Audi"){
        brand_name = "VW";
      }
    private:
      std::string brand_name;
    };
    
    • Ändern der Interna der Basisklasse bricht abgeleitete Klasse

    Dies funktioniert

    int foo;
    
    class Base{
    private:
      int bar;
    };
    
    class Derived:public Base{
    public:
      void my_func(){
        foo = 4;
      }
    };
    

    So nun wird Base geändert und es geht nicht mehr:

    class Base{
    private:
      int foo;
    };
    

    (Ist kein Compiler-Bug sondern ein Standard-Bug)

    Wer noch Kandidaten hat kann sie ja einfach mal nennen. Vielleicht macht ja irgendwer mal ein Artikel draus.



  • Sieht nett aus. 🙂



  • Hallo

    Reihenfolge in der Initialisierungsliste ist auch ein guter Kanidat.

    chrische



  • Off-by-one Fehler, die sich erst viel später auswirken. Folgendes Beispiel hatte ich sinngemäß erst vorgestern, wobei die Funktion "func" nicht von mir war und nur compiliert vorlag :(. Habs dann über nen Watchpoint gefunden. (Ist aber ANSIC).

    void func( char* buffer, size_t length ) {
        buffer[ length ] = '\0';
        strcpy( somewhere, buffer );
    }
    
    void use() {
        char buffer[ 2000 ];
        char hostname[ 256 ];
    
        strcpy( hostname, "My_Pc" );
        func( buffer, sizeof( buffer ) ); // wenn die stack-ausrichtung stimmt ist hostname jetzt leer
    }
    


  • Ben04 schrieb:

    • Selbstinitialisierung
    class Car{
    public:
      Car(const std::string&brant_name):
        brand_name(brand_name){}
    private:
      std::string brand_name;
    };
    

    Wo ist das Problem?

    Aber im Grunde glaube ich nicht das man daraus einen guten Artikel schreiben kann und vor dem meisten warnen die Compiler ja, wenn es nicht sogar einen Fehler generiert.



  • Ich denke schon, dass man da insgesamt was nettes schreiben kann. Allerdings denke ich nicht, dass es genügt eine Liste von Bugs zu machen und zu sagen: "Boah, die waren alle soo schwer zu finden."

    Wie bereits eindrucksvoll bestätigt (ich wollte gestern schon antworten, dachte aber ich warte noch bis sich jemand meldet, danke ;)) wird es immer einen geben, der so einen Bug anschaut und sagt: "Öh, der is doch voll einfach zu finden. Ist ja garkein Problem."

    Vielmehr sollten in so einen Artikel dann auch Tipps/Tricks und Techniken rein, die helfen genau diese Fehler zu finden oder gleich zu vermeiden. Vieles davon kann man sehr leicht über Unit-Tests rausfinden. Bei anderen Sachen hilft vielleicht eine klare Namenskonvention. Wer beispielsweise wie ich Parameter und Member nicht gleich benennt, dem kann manches davon garnicht passieren etc.



  • Kann überhaupt ein einziger Autor solch eine Liste aufschreiben? Man, der muß ja echt Probleme gehabt haben. 😃 😉

    Wenn dann kann man doch nur sowas sammeln. Was ja hier in diesem Thread passiert. Und ich will mich mal anschliessen.

    Ich hatte mal ein switch-case-Konstrukt. nichts spektakuläres:

    switch(a)
    {
       case right:
            rechts();
            break;
       case left:
            links();
            break;
       case down:
            runter();
       case up:
            hoch();
            break;
    }
    

    Tja, und ich habe ewig gesucht, woran das Problem liegen könnte. Nur nicht im switch-case-Konstrukt! Weil ich den Fehler erst später bemerkt habe, kam ich nicht auf die Idee dort zu suchen.

    Was habe ich daraus gelernt? zu jedem case überprüfe ich heute instinktiv ob ich auch ein passendes break habe. Sobald ich case schreibe, hau ich sofort ein break rein. Egal was kommt! Das break kann ich immer noch weg nehmen, wenn ich es doch nicht brauche.



  • Artchi schrieb:

    Was habe ich daraus gelernt? zu jedem case überprüfe ich heute instinktiv ob ich auch ein passendes break habe. Sobald ich case schreibe, hau ich sofort ein break rein. Egal was kommt!

    Genau das meine ich, sowas gehört in sonen Text auf jeden Fall mit rein.

    Das break kann ich immer noch weg nehmen, wenn ich es doch nicht brauche.

    Und dann hoffentlich nen Kommentar, damit's bei der nächsten Fehlersuche nicht von jemand anders blind reingesetzt wird "klar, dass das nicht tut, da fehlt ja 'n break".



  • Artchi schrieb:

    Tja, und ich habe ewig gesucht, woran das Problem liegen könnte. Nur nicht im switch-case-Konstrukt!

    single-step im debugger, dann hätteste es leicht gefunden 😉

    Artchi schrieb:

    Was habe ich daraus gelernt? zu jedem case überprüfe ich heute instinktiv ob ich auch ein passendes break habe. Sobald ich case schreibe, hau ich sofort ein break rein. Egal was kommt! Das break kann ich immer noch weg nehmen, wenn ich es doch nicht brauche.

    ich würde aber noch einen kommentar hinschreiben,
    mindestens: */* Intentionally no BREAK here /
    sonst baut man später noch ein break ein, weil man meint es vergessen zu haben. 😃
    edit: zu laaahhhhm 😞

    topic: am schlimmsten finde ich bugs, die man nicht selber fabriziert hat, z.b. falsch funktionierende library-funktionen und dergleichen...
    🙂



  • Ich werde immer mal wiede rausgelacht, weil ich IMMER Klammern setze.
    Ich habe grundsätzlich zu viele Klammern... egal ob () oder {}

    Allerdings ist mir sowas lieber als die Sucherei, warum das immer Meldung macht und nicht nur, wenn x, was es soll:

    if (x == 3)
        tuwas();
        MachMeldung();
    tuwasanderes();
    

    Und: Schöner Fehler, den ich grade aus Versehen drin hatte:

    if (x = 3)
        tuwas();
        MachMeldung();
    tuwasanderes();
    

    ...für runde Klammern fällt mir grade nix ein...



  • estartu schrieb:

    Und: Schöner Fehler, den ich grade aus Versehen drin hatte:

    if (x = 3)
        tuwas();
    

    schreib das nächste mal if (3==x)
    🙂



  • Das finde ich persönlich echt häßlich... auch wenn's gegen sowas hilft.



  • pale dog schrieb:

    estartu schrieb:

    Und: Schöner Fehler, den ich grade aus Versehen drin hatte:

    if (x = 3)
        tuwas();
    

    schreib das nächste mal if (3==x)
    🙂

    Wie schon jemand weiter oben sagte: Einige Fehler lassen sich durch Konventionen vermeiden.

    Bei mir fangen alle Member mit m_ und alle Parameter mit f_ an... schon kann mir das eine genannte Beispiel nicht passieren. 😉



  • Jester schrieb:

    Artchi schrieb:

    Was habe ich daraus gelernt? zu jedem case überprüfe ich heute instinktiv ob ich auch ein passendes break habe. Sobald ich case schreibe, hau ich sofort ein break rein. Egal was kommt!

    Genau das meine ich, sowas gehört in sonen Text auf jeden Fall mit rein.

    Allerdings sollte es begründet sein und da helfen nun einmal konkrete Beispiele damit das ganze nicht in der Luft hängt und man überzeugend wirkt. Man braucht also beides.

    Der erste Fehler hat bei mir dazu geführt, dass ich sobald es unerklärliche Abstürze gibt in jeden Copykonstruktor ein

    assert(&other != this);
    

    rein tue. Hilft oft den Fehler zu finden. Einfach mit dem Debugger warten bis der assert fliegt dann noch einmal kurz einen Stacktrace und der Fehler ist behoben.

    Artchi schrieb:

    Kann überhaupt ein einziger Autor solch eine Liste aufschreiben? Man, der muß ja echt Probleme gehabt haben.

    Natürlich kann eine solche Liste nicht komplett sein allerdings geht die Fehlersuche schneller je mehr mögliche Fehler man kennt.

    ...für runde Klammern fällt mir grade nix ein...

    1 << 2&6 schreiben wo 1 << (2&6) gemeint ist. Bei solchen Operatoren setze ich auch immer Klammern.

    Mir schwebte eher ein Artikel vor welcher ungewöhliche Fehler darstellt und erklärt also eher ein Kuriositätenkabinett als ein Artikel der Tipps gibt wie man Fehler verhindert. Wer kannte Bug Nummer 3 im ersten Post bevor er hier gelesen hat? Beinahe alle (alle?) Bücher sagen, dass private dazu dient die Implementation zu verstecken, also wieso sollte es einen Einfluss auf abgeleitete Klassen haben? Ich glaube da wären viele erstaunt zu sehen, dass diese Kapselung doch nicht immer so ganz dicht ist.

    Das Beispiel mit if(a = 3) ist natürlich ein sehr häufiger der glaub ich bereits von jedem mindestens einmal gemacht wurde. Ein Weg ihn zuverlässig zu verhindern wäre sicher interessant hat aber in einem Kuriositätenkabinett nichts zu suchen da er allgemein bekannt ist.

    Der Nutzen eines Artikels welcher sich mit der Fehlersuche allgemein beschäftigt sehe ich auch allerdings wäre das glaub ich ein anderer. Beispiel #3 hätte in dem nichts zu Suchen da es einen, in meinen Augen, wenig praxisnaher Bug ist.

    Das wären dann schon zwei Vorschläge. 🙂



  • int Koordinate[_SIZE]={0};
    
    // später bei der Eingabe:
    
    if( Eingabe < 0 || Eingabe > _SIZE ) WirfFehlerMeldung();
    else SchreibInsArray();
    

    Und ich such eine halbe Stunde, warum da ständig was über die Arraygrenzen rausfliegt...

    Toffi



  • was gibt das aus?

    int a = 1;
    printf ("%d-%d-%d\n", a++, a++, a);
    

    1-2-3 oder was anderes?
    🙂



  • pale dog schrieb:

    was gibt das aus?

    int a = 1;
    printf ("%d-%d-%d\n", a++, a++, a);
    

    1-2-3 oder was anderes?
    🙂

    Und wieder ein klassisches Beispiel für undefiniertes Verhalten - dort könnte nahezu alles von 1-1-1 bis 3-3-3 hinten rauskommen (OK, mir fällt gerade keine Auswertereihenfolge ein, die letzteres produziert), je nachdem in welcher Reihenfolge der printf()-Ausdruck ausgewertet wird.



  • Ben04 schrieb:

    Jester schrieb:

    Genau das meine ich, sowas gehört in sonen Text auf jeden Fall mit rein.

    Allerdings sollte es begründet sein und da helfen nun einmal konkrete Beispiele damit das ganze nicht in der Luft hängt und man überzeugend wirkt. Man braucht also beides.

    Stimmst Du mir da zu? Ich verstehe nicht was Du damit sagen willst, klingt irgendwie als wolltest Du mir widersprechen, wobei ich da den Punkt nicht sehe. 😕



  • Wollte eher verdeutlichen/betonen, dass beide Teile wichtig sind, widersprechen wollte ich eigentlich nicht. Das "Allerdings" war fehl am Platz.



  • Ich hatte heute was nettes:

    class Basis
    {
    public:
        virtual void tuwas(int bla);
    };
    
    class Extended : public Basis
    {
    public:
        virtual void tuwas(int bla);
    };
    

    Und auf der "obersten" Ebene gibt es zig abgeleitete Klassen wie z.b.

    class Spezial : public Extended
    {
    public:
        virtual void tuwas(int bla);
    };
    

    Und irgendwo ruft man das dann über die Basisklasse auf:

    Spezial blub;
    Basis* pBasis = &blub;
    pBasis->tuwas(3);
    

    Soweit, alles prima. 👍

    Nun funktioniert der Code monatelang super.
    Man muss, wie das so ist immer wieder hier und da was anpassen.
    Und dann mach man sowas:

    class Spezial : public Extended
    {
    public:
        virtual void tuwas(int bla, bool blub);
    };
    

    Und schon tut der Aufruf nicht mehr, was man von ihm gewohnt ist. 😮
    Weil nämlich nicht wie erwartet Spezial::tuwas aufgerufen wird sondern Extended::tuwas. ⚠

    Liegt eine solche Änderung auch noch mehrere Tage zurück und war wegen einer ganz anderen Funktion als da wo der Fehler auftritt, sucht man sich dumm und dusselig. 🙄


Anmelden zum Antworten