Meine liebe Hassliste



  • cooky451 schrieb:

    Du denkst da an den falschen Anwendungsfall. Manchmal will man einfach nur 100 MB Speicher am Stück haben, der dann später beschrieben wird - std::vector fährt da dann erstmal mit einem memset drüber. 😉 Aber ja, die Anwendungsfälle halten sich schon in Grenzen, ist nur etwas, das mir eingefallen ist.

    Ja, dafür dann den MemoryPool. Apache macht es vor. Wobei der Hauptvorteil davon ist, daß kein Destruktor befragt wird.

    Daß vector aber die 100MB vorher nullen wüprde, ist schlicht falscht.
    vector<char> v(100000000) tut es. Und dann reinkopieren mit v[i++]=c;
    Aber das fast immer bessere
    vector<char> v; nebst v.push_back(c);
    ist davon frei.



  • cooky451 schrieb:

    Du denkst da an den falschen Anwendungsfall. Manchmal will man einfach nur 100 MB Speicher am Stück haben, der dann später beschrieben wird

    Und ohne ihn zu nullen? Dann geht doch push_back perfekt. Wir konstruieren einfach hinein.
    Ähm, ob ich den i++ selber führe oder der vector. Ja, Registerdruck, falls i ind c.size() immer gleich sind. Falls ungleich, ist es schon recht egal.

    Oder DU willst ausnutzen, daß auf Deinem BS der allokierte Speicher schon genullt ist? Nee, so fies bist Du nicht, das weiß ich.



  • Na ja, angenommen du willst 100 MB binäre Daten einfach am Stück in den Speicher schaufeln (aus einer Datei z.B.) - da ließt du doch nicht immer ein byte auf einmal und pushst das dann in der vector? 😃



  • ...



  • Swordfish schrieb:

    volkard schrieb:

    [...]

    Aha. Also

    if(foo()){
        bar(42)
    }
    

    .

    Und noch vier- bis fünfmal [Strg]+[+] drücken bitte.



  • cooky451 schrieb:

    Na ja, angenommen du willst 100 MB binäre Daten einfach am Stück in den Speicher schaufeln (aus einer Datei z.B.) - da ließt du doch nicht immer ein byte auf einmal und pushst das dann in der vector? 😃

    Naja, vielleicht benutzue ich dann Filemapping und fresse gar keinen Speicher weg.
    Aber jo, ein "Container" für nicht konstruierten Speicher, der fehlt irgendwie.



  • if( x < y){
           //...
    } else {
           //...
    }
    

    liest sich beschissen.



    • eigenen vektor definieren, weil er "besser" ist als der Standard
    • wegen Formatierung eine Diskussion anfangen als gäbe es nicht wichtigeres


  • Meine unvollständige Hassliste, sortiert nach Kategorie.

    Ressourcenleck
    - Destruktoren, die mehrere Ressourcen manuell freigeben (weil starkes Anzeichen für Lecks beim Anfordern)

    • delete , delete[] , free , myPrefix_Free
      - Nichtverwendung von Initialisierungslisten
    • destroy() -Methode statt Destruktor
      - Verwendung von nicht-trivialen C-Bibliotheken ohne irgendwelche Wrapper
    • exit

    Undefiniertes Verhalten
    - reservierte Bezeichner (besonders gerne als _INCLUDE_GUARD_H_ )
    - Missachtung von strict aliasing oder alignment
    - falsche Verwendung von union

    • signed Overflow

    Unnötige Gefahr / Obfuscation

    • #define für Konstanten
      - globale/statische Variablen
      - Annahme, dass sizeof(int) == sizeof(long) == 4 etc.
      - C-Casts
      - magische Zahlen
    • int oder unsigned , wenn eigentlich ptrdiff_t oder size_t gemeint ist
      - riesige Klassen in riesigen Dateien
    • strcpy , strlen , atoi , fopen , memcpy usw.
    • s/f/printf
      - geschweifte Blockklammern bei Einzel-Statements weglassen
      - Klassenmember in einem #ifdef (endet immer in kaputtem Build oder undefiniertem Verhalten)
      - Statements in #ifdef
      - Kommaoperator statt Statements

    Voodoo
    - Werte im Destruktor in Nullzustand setzen ( v.clear() , p = nullptr etc.)
    - "safe delete"-Makros oder -Funktions-Templates

    • if (p) { delete p; }
    • inline bei Definition in cpp-Datei
      - lokale Arrays, wo vector oder string besser geeignet wären
    • typedef struct

    Unwissenheit

    • ntohl , ntohs und so
    • struct zur "Serialisierung"
      - Verwendung von std::list , wenn std::vector gemeint ist
    • throw new
      - C-Standard-Header einbinden
      - Spaces zum Einrücken
    • while (!feof(f)) und ähnliche Abenteuer

    In den meisten Projekten finden sich leider die meisten dieser Punkte.



  • Swordfish schrieb:

    hustbaer schrieb:

    * Plenken funktion ( parameter );

    Fällt

    if( !foo ) { bar( 43 ); }
    

    in das Schema?

    Ja.
    Das sind 3 Sachen auf einmal, wobei ich eins vergessen hatte hinzuschreiben: "ifs" wo die bedingte Anweisung (bzw. der Block) in der selben Zeile mit dem "if" steht.

    Also Schritt für Schritt...
    Zwei Zeilen draus machen

    if( !foo )
        bar( 43 );
    

    Plenks entfernen

    if(!foo)
        bar(43);
    

    Fehlendes Leerzeichen nach dem Keyword einfügen

    if (!foo)
        bar(43);
    

    Tadaa 🙂



  • TyRoXx schrieb:

    Ressourcenleck
    - Destruktoren, die mehrere Ressourcen manuell freigeben

    Der Destruktor ist dabei ja nicht das Problem, sondern der (meist nicht Exception-sichere) Konstruktor den man dazu braucht.

    Aber guter Punkt grundsätzlich. Ganz schlimm: Code der fleissig Exceptions verwendet, aber an 1000 Stellen nicht Exception-sicher ist.



  • TyRoXx schrieb:

    - Destruktoren, die mehrere Ressourcen manuell freigeben (weil starkes Anzeichen für Lecks beim Anfordern)

    Sehr schöner Punkt 👍 und immer wieder ein relativ gutes Zeichen für halb verstandenes RAII.

    TyRoXx schrieb:

    Missachtung von strict aliasing

    Da fehlt noch Alignment. Aber wenn jemand speziell für eine Plattform programmiert ist das schon okay denke ich. Strict aliasing scheint eh niemand so richtig zu verstehen.

    TyRoXx schrieb:

    • strcpy , strlen , atoi , fopen , memcpy usw.

    memcpy ist schon okay denke ich. Auch an fopen sehe ich grundsätzlich nichts Falsches, wenn es ordentlich gekapselt ist.

    TyRoXx schrieb:

    - geschweifte Blockklammern bei Einzel-Statements weglassen

    😞 Wie sieht's hiermit aus?

    for (unsigned i = its + 1; --i != 0; )
      if (foo(i) == its)
        return bar(++i), baz(its), i;
    

    TyRoXx schrieb:

    - lokale Arrays, wo vector oder string besser geeignet wären

    Oder std::array? Man sollte die Vorzüge des Stacks nicht so oft missen, finde ich.



  • cooky451 schrieb:

    TyRoXx schrieb:

    • strcpy , strlen , atoi , fopen , memcpy usw.

    memcpy ist schon okay denke ich.

    Mir sind die impliziten Konvertierungen zu void * zu gefährlich.
    Bei std::copy kann der Compiler viel leichter Fehler entdecken.

    cooky451 schrieb:

    Auch an fopen sehe ich grundsätzlich nichts Falsches, wenn es ordentlich gekapselt ist.

    Wie wäre es mit i/o/fstream ?

    cooky451 schrieb:

    TyRoXx schrieb:

    - geschweifte Blockklammern bei Einzel-Statements weglassen

    😞 Wie sieht's hiermit aus?

    for (unsigned i = its + 1; --i != 0; )
      if (foo(i) == its)
        return bar(++i), baz(its), i;
    

    Stimmt, den Kommaoperator habe ich vergessen.

    cooky451 schrieb:

    TyRoXx schrieb:

    - lokale Arrays, wo vector oder string besser geeignet wären

    Oder std::array? Man sollte dir Vorzüge des Stacks nicht so oft missen, finde ich.

    Wenn die Größe wirklich klein und fest ist, kann man std::array verwenden.
    Wenn die Größe variabel und nur selten zu groß für den Stack ist, kann man sich ein small_vector<T, N> -Template schreiben.
    Ansonsten möge man einen dynamischen Standard-Container nehmen.



  • TyRoXx schrieb:

    Mir sind die impliziten Konvertierungen zu void * zu gefährlich.
    Bei std::copy kann der Compiler viel leichter Fehler entdecken.

    Hm, sehe ich nicht unbedingt so. memcpy sagt ja gerade "schreib einfach in den Speicher". std::copy ist da nur bedingt ein Ersatz. z.B. hier:

    void foo(const void* data, std::size_t size)
    {
      int s;
      memcpy(&s, data, sizeof s);
      // vs
      copy(static_cast<const uint8_t*>(data), static_cast<const uint8_t*>(data) + sizeof s, reinterpret_cast<uint8_t*>(&s));
    }
    

    Und warnen kann der Compiler bei den ganzen Casts dann auch nicht mehr viel. Insofern, ich halte copy und memcpy einfach für zwei verschiedene Dinge. memcpy benutze ich, wenn ich mit Speicher hantiere. copy ist für Objekte.

    TyRoXx schrieb:

    Wie wäre es mit i/o/fstream ?

    Ich mag die C++-Streams einfach wirklich, wirklich, wirklich nicht. 😉



  • Hallo 🙂

    Wenn man so verliebt ist in eine Sprache das eher diese bedient wird
    als der Anwender und/oder Computer.
    ("Zu jeder Tätigkeit das passende Werkzeug benutzen")

    Das es im Internet keinen update-Button gibt
    und sich dadurch falsche Annahmen/Code soweit verbreiten
    bis jeder glaubt es wäre der richtige Weg.
    ("Mehrfache Wiederholung machen Unwahrheiten kein bischen wahrer")

    Ohje 😃



  • Dinge die ich nicht mag:
    * Fehlende Dokumentation
    * Dateipaare welche eigentlich in mehrere Dateien zerfallen sollten, aber wo man diese der "Übersichtlichkeit" halber in eine Datei gepackt hat
    * Fehlende Trennung der Funktionalitäten s.d. diese man auch Allgemeiner benutzt werden könnte.

    void CryptAndWriteData(FILE* File, const char* Data, const char* Key)
    {
      while (*Data)
      {
        fprintf(File, "%c", *Data ^ Key[i]);
        Data++;
        i = (i + 1) % strlen(Key);
      }
    }
    

    * Mehrere Anweisung in einer Zeile (schlecht zu debuggen)
    * Mikro-Optimierungen nach dem Motto: Ich weis es besser als der Compiler.
    * Übergabe von Funktionsparameter mittels globalen Variablen:

    void OpenPortAndGetData(void);
    

    * Globale Variablen, wenn diese an Funktionen gebunden sind.
    * Statische Variablen innerhalb einer Funktion
    * Makro's
    * Fehlende Typsicherheit:

    unsigned char Sprache;
    //...
    if (Sprache == DEUTSCH)
    //...
    
    void Test(unsigned int Flags)
    {
    //...
      Test2(Flags)
    }
    

    * exit
    * Allokierung von Resourcen welche nicht freigegeben wurden, da Windows diese ja automatich freigibt
    * char*, char s[37]
    * Zugriff auf statische Array's ohne Überprüfung eines Überlauf's
    * Statische Array's wo eigentlich std::vector
    * Fehlende Const Correctness
    * CRT
    * "Never change a running system" bis zum Exzess



  • Bitte ein Bit schrieb:

    * exit

    Ich hatte neulich exit benutzt, damit das Programm nach Berechnung des Ergebnisses nicht noch Minutenlang den Speicher aufräumt. 🕶



  • Ich hatte neulich exit benutzt, damit das Programm nach Berechnung des Ergebnisses nicht noch Minutenlang den Speicher aufräumt.

    Kommt halt immer auf den Fall an.

    Ich habe es erlebt das man exit() in einer Error-Funktion benutzte. Trat ein Fehler auf, wurde die Funktion aufgerufen und peng. Dumm nur, Zwischenergebnisse, welche in einer Datei geschrieben wurden, waren weg, obwohl diese sehr bruachbar waren.

    Übrigens:
    Was muss man tun damit man minutenlang Speicher aufräumt? Wieviel GByte swappst du da?



  • Bitte ein Bit schrieb:

    Was muss man tun damit man minutenlang Speicher aufräumt? Wieviel GByte swappst du da?

    Man muss einfach nur ohne Ende Mini-Allocations machen, das reicht schon. Wenn man exit() aufruft wird der Speicher von Windows allerdings mehr oder weniger instant freigegeben.



  • Im Produktionscode von Arbeitskollegen:

    void FOO()
    {
       if( abc )
       {
          some_type* x;
          x = NULL;
          x = new some_type();
          if( x )
          {
             ...
          }
       }
    }
    
    int abc;
    
    void bar()
    {
       abc = 7;
       FOO();
    }
    

    Der Quelltext ist mehrere tausend Zeilen lang, hin- und wieder werden globale Variablen zwischen Funktionsrümpfen untergebracht, da können aber auch einige hundert Quelltextzeilen zwischen Deklaration und Benutzung liegen.


Anmelden zum Antworten