Wo leake ich hier memory? Dynamic array


  • Mod

    Mein Code funktioniert jetzt auf dem Testserver, auch wenn ich immer noch eine Warning bekomme und memory geleakt wird.

    Es gibt schon einen Grund, warum in der ersten Antwort stand und auch oft wiederholt wurde:

    @SeppJ sagte in Wo leake ich hier memory? Dynamic array:

    Wenn du wissen möchtest, wie man korrekt programmiert: Schlag das Stichwort RAII nach. Das ist ein grundlegendes C++-Programmiermuster, bei dem jeder Ressourcenanforderer selber für die Freigabe verantwortlich. Wenn er das korrekt macht (ist nicht so schwer), dann kann auch nix mehr schief gehen.

    Wenn du das getan hättest und dein Programm nach diesen Maßgaben neu programmiert hättest, dann wärst du längst fertig und hättest zudem was nützliches über C++ gelernt. Mit deinem momentanen Ansatz wirst du nie ein sauberes Ergebnis erhalten und das wenige, was du dabei lernst, ist wie man sich das Leben unnötig schwer macht.



  • @wob
    😁
    Stimmt! Sehe ich zum ersten Mal. Jetzt fällt auch noch meine Ausrede "hab ich aus den Coreguidelines übernommen" flach. Danke dafür 😉



  • @marcel91200 sagte in Wo leake ich hier memory? Dynamic array:

    Die bool isPermutation(int *perm, int count) Funktion bekommt ein Array uebergeben und ueberprueft ob ausschliesslich jede Zahl von 0 bis count-1 in diesem vorkommt.

    Aha! Dann ist nur der Name der Funktion schlecht, eben weil man an das std::is_permutation denkt, das ja etwas anderes tut. Nenne es doch isPermutationsOfFirstNaturalNumbers - oder denk dir was besseres, kürzeres aus 😉

    Jendenfalls hast du da noch einen Fehler drin:

    int *cmp = new int[size];

    Dieser Code initialisiert die Werte in cmp nicht. Du brauchst aber eine Initialisierung, weil du nachher alle Werte mit 1 vergleichst.
    => nimm stattdessen int *cmp = new int[size]{}; (die {} machen den Unterschied) - und schon werden alle ints mit 0 initialisiert (bool statt in täte es hier natürlich auch). Das std::make_unique<int[]>(size) oder ein std::vector<int>(size) initialisieren automatisch.

    bool isSorted(double *data, int dataCount, int *perm) schaut dann ob unsere Permutation (also das Indizes-Array) kombiniert mit dem anderen Eingabe-Array eine sortierte Liste hervorbringt.

    Ah! Und schon wieder ist das Naming verbesserungswürdig. Und noch ein genereller Tipp: in C++ wird zur Sortierung standardmäßig normalerweise kleiner-als verwendet. Dein Test mit größer-als geht natürlich auch, aber es ist mehr oder weniger Konvention, solche Tests immer mit dem kleiner-als-Operator durchzuführen.

    PS: @SeppJ hat mit seinem Rat recht, allerdings hilft der dir natürlich nur für die reale Welt, aber nicht für deine Übungsaufgaben.


  • Mod

    @wob sagte in Wo leake ich hier memory? Dynamic array:

    PS: @SeppJ hat mit seinem Rat recht, allerdings hilft der dir natürlich nur für die reale Welt, aber nicht für deine Übungsaufgaben.

    Wieso nicht? Vorgabe war, nicht vector, array, etc. zu nutzen. Es hindert ihn doch keiner, die 25 Zeilen für eine eigene vector-Implementierung zu schreiben und damit dann alle Aufgaben trivial in 3 Zeilen zu lösen. Da macht er effektiv das gleiche, was er hier von Hand erfolglos versucht, bloß mit Richtigkeitsgarantie, und lernt zudem noch, wie ein vector funktioniert.



  • Wie gesagt, die Funktionsnamen wurden vorgegeben, genauso wie die Parameter. Daran sollen wir nichts aendern (dann funktioniert auch der automatische Test nicht mehr), da muesst ihr euch bei meinem Prof (oder wer auch immer sich das alles ausdenkt) beschweren ^^

    @SeppJ sagte in Wo leake ich hier memory? Dynamic array:

    Wieso nicht? Vorgabe war, nicht vector, array, etc. zu nutzen. Es hindert ihn doch keiner, die 25 Zeilen für eine eigene vector-Implementierung zu schreiben und damit dann alle Aufgaben trivial in 3 Zeilen zu lösen.

    Die Aufgabe war, dass wir dies mit einem dynamischen Array loesen sollen und uns somit auch gleich die Speicherzuweisung anschauen, da ist nichts mit "eigene vektor klasse implementieren". Es geht eben darum die einzelnen Konzepte zu verstehen und nicht einfach ne vektor klasse ausm Internet zu kopieren (was sicherlich viele machen wuerden)
    RAII schaue ich mir aber an, danke fuer den Tipp.



  • @marcel91200 sagte in Wo leake ich hier memory? Dynamic array:

    Wie gesagt, die Funktionsnamen wurden vorgegeben, genauso wie die Parameter. Daran sollen wir nichts aendern (dann funktioniert auch der automatische Test nicht mehr), da muesst ihr euch bei meinem Prof (oder wer auch immer sich das alles ausdenkt) beschweren ^^

    Poste mal die Angabe 1:1.



  • @marcel91200 sagte in Wo leake ich hier memory? Dynamic array:

    Mein Code funktioniert jetzt auf dem Testserver, auch wenn ich immer noch eine Warning bekomme und memory geleakt wird. Danke fuer die Hilfe
    HEAP SUMMARY:
    in use at exit: 72,704 bytes in 1 blocks
    total heap usage: 4 allocs, 3 frees, 72,764 bytes allocated

    Da steht "still reachable":

    ==24991== LEAK SUMMARY:
    ==24991==    definitely lost: 0 bytes in 0 blocks
    ==24991==    indirectly lost: 0 bytes in 0 blocks
    ==24991==      possibly lost: 0 bytes in 0 blocks
    ==24991==    still reachable: 72,704 bytes in 1 blocks
    ==24991==         suppressed: 0 bytes in 0 blocks
    

    Das ist oft "normal". Das kann z.B. ein Puffer der libc sein der 1x angefordert und nie wieder freigegeben wird.
    Die echten Probleme waren die ganzen Zugriffe auf nicht initialisierten Speicher.



  • @marcel91200 ja, wir haben schon verstanden, dass der Prof YAIT (yet another incompetent teacher) ist.



  • @hustbaer sagte in Wo leake ich hier memory? Dynamic array:

    Das ist oft "normal". Das kann z.B. ein Puffer der libc sein der 1x angefordert und nie wieder freigegeben wird.

    Ja ne, dann ist trotzdem was kaput.



  • @Swordfish sagte in Wo leake ich hier memory? Dynamic array:

    @hustbaer sagte in Wo leake ich hier memory? Dynamic array:

    Das ist oft "normal". Das kann z.B. ein Puffer der libc sein der 1x angefordert und nie wieder freigegeben wird.

    Ja ne, dann ist trotzdem was kaput.

    Wieso? Nicht akkumulierende "Leaks" gibt's häufig. Sind IMO auch völlig OK. Wozu Verränkungen versuchen um Zeugs beim Prozessende freizugeben wenn das OS sowieso den ganzen Prozess weg macht?


  • Mod

    @hustbaer sagte in Wo leake ich hier memory? Dynamic array:

    Das ist oft "normal". Das kann z.B. ein Puffer der libc sein der 1x angefordert und nie wieder freigegeben wird.
    Die echten Probleme waren die ganzen Zugriffe auf nicht initialisierten Speicher.

    Das sollte dann aber 'suppressed' sein, wenn's aus der Standardbibliothek oder anderem (für valgrind bekannten) 3rd-Party-Code kommt. Der "still reachable" wird schon aus dem Programm des OP kommen, und wen wundert das bei diesem Programmaufbau? Es ist zwar technisch gesehen kein richtiger Leak, aber das Übungsziel, sauber mit dynamischem Speicher umzugehen, wurde trotzdem verfehlt (wobei das bei diesem Lehrer aber auch unmöglich zu schaffen scheint).



  • @SeppJ sagte in Wo leake ich hier memory? Dynamic array:

    wobei das bei diesem Lehrer aber auch unmöglich zu schaffen scheint

    deswegen @marcel91200

    @Swordfish sagte in Wo leake ich hier memory? Dynamic array:

    Poste mal die Angabe 1:1.



  • @SeppJ sagte in Wo leake ich hier memory? Dynamic array:

    Das sollte dann aber 'suppressed' sein, wenn's aus der Standardbibliothek oder anderem (für valgrind bekannten) 3rd-Party-Code kommt.

    Sollte: ja, vielleicht. Ich hab das aber in echt schon öfter gesehen. Ist auch verdächtig dass es jedes mal genau 71k sind. Und ich seh in dem Code auch kein Leak. Grausig, ja, aber Leak kann ich da keins finden. Also wenn man mal davon absieht dass das ganze natürlich nicht Exception-safe ist, und im Fall einer Exception natürlich schon leaken kann.



  • @marcel91200 sagte in Wo leake ich hier memory? Dynamic array:

    double *getDynArray(int &size)
    {
        double *array = new double[0];
    

    @hustbaer T'schuligorn? Aber nach solchen Dämlichkeiten liest Du noch weiter? Respekt.



  • Anstatt einem Anfaenger einfach mal zu erklaeren was an einem Ausdruck falsch ist, kommen zum Grossteil (nicht von jedem) nur solche Sprueche? Versteh den Sinn hinter solchen Kommentaren nicht. Ebenso bringt es wenig eine standard Bibliothek zu nutzen, wenn man ein gewisses Konzept nicht verstanden hat, dann funktioniert es zwar, aber man lernt nichts dabei. Wunderschoener Umgangston hier teilweise...


  • Mod

    Wie es richtig geht, wurde in der ersten Antwort gesagt. Sowohl wie man richtig die Standardbibliothek nutzt, als auch wie man es richtig selber machen würde. Wenn du trotzdem an deinem Ansatz festhältst und nicht auf die Hilfestellungen eingehst, kommt halt früher oder später so etwas.



  • @marcel91200 Würdest Du bitte 1:1 die f*cking Aufgabe posten?



  • @marcel91200 sagte in Wo leake ich hier memory? Dynamic array:

    Anstatt einem Anfaenger einfach mal zu erklaeren was an einem Ausdruck falsch ist

    Der gesamte Ansatz ist Müll. Sorry. Das wird leider oft so gelehrt. Man kann es also nicht an einer Zeile oder so festmachen, denn der konzeptionelle Ansatz ist verkehrt. Ich habe dir den Link aus den Code-Guidelines gepostet. Wenn du new und/oder delete irgendwo im Programm hast und das nicht in einer speziell dafür gemachten Ressourcen-Handler-Klasse ist, dann taugt das Programm nichts. So einfach! Wenn dein Prof lehrt, dass ihr new und delete irgendwie einfach so im Programm benutzen sollt, dann kann er/sie nicht ordentlich in C++ programmieren. Häufig wird ein Mischmasch aus C und C++ gelehrt und im Endeffekt weder das eine noch das andere korrekt und idiomatisch.

    Bitte lies dir auch durch, was RAII bedeutet:
    https://en.wikipedia.org/wiki/Resource_acquisition_is_initialization
    https://en.cppreference.com/w/cpp/language/raii
    https://isocpp.github.io/CppCoreGuidelines/CppCoreGuidelines#Rr-raii
    Das ist ein extrem wichtiges Konzept in C++. Wenn man es nicht befolgt (und dein Ansatz tut das nicht), dann kommen Programme heraus, die extrem fehleranfällig sind.

    Der Ton mag hier manchmal etwas hart sein, aber es nervt, wenn man gegen inkompetente Lehrkräfte ankämpfen muss, die ihren Studenten Dinge nicht ordentlich beibringen.

    Daher: wir haben hoffentlich dein Programm halbwegs so verbessert, dass du damit die Aufgabe erfüllst, aber so würde man das in ordentlichem C++ niemals machen. Nur wenn hier immer Bedingungen vorgegeben werden wie "keine STL", "keine eigene vector-Klasse", dann kann man das Problem eben nicht ordentlich lösen.

    Wunderschoener Umgangston hier teilweise...

    Bitte störe dich nicht daran, denn fachlich kompetent sind die Antworten, auch wenn der Ton manchmal etwas gröber ist. Auch wenn dir hier Fragen gestellt werden, ist das häufig mit der Intention, dass du darüber nachdenkst.



  • Ich hab gerade kurz RAII angeschaut und wollte nur mal fragen ob solch ein Ansatz demnach besser waere:

    struct dynamicArray
    {
        double *p;
        int size;
    
        void resize(int newSize)
        {
            p = (double *)realloc(p, newSize * sizeof(double));
            size = newSize;
        }
    
        dynamicArray(int newSize)
        {
            p = (double *)malloc(newSize * sizeof(double));
            size = newSize;
        }
        ~dynamicArray() { free(p);}
    };
    

    Waere das so richtig? Ich lagere dann das dynamische Array in ne eigene struct oder in ne eigene Klasse aus, da ich somit ja keine Bedenken mehr zwecks Speicherdeallozierung haette, da ja der Destructor dies, nach ende der Lebenszeit des Objekts, fuer mich uebernimmt.
    (Aequivalent haette man natuerlich auch new double[newSize] im Constructor nehmen koennen, falls das so richtig ist)

    Haette ein unique_ptr dem gegenueber irgendeinen Vorteil, ausser dass man sich den "Aufwand" ne eigene struct/klasse zu erstellen spart?



  • Naja, das wäre schon mal ein Ansatz.

    Gut: realloc (C) tut, sofern du nur POD-Werte hast, genau das richtige.

    Rat: Beginne Klassen mit Großbuchstaben. Also: DynamicArray.

    Du könntest genausogut new und delete verwenden. Sobald du nicht nur "double" erlauben willst, sondern beliebige Typen, ist malloc/free (das ist C!) keine Option mehr und du musst new/delete verwenden und realloc funktioniert dann nicht mehr. Solange du "einfache Typen" hast, ist realloc die optimale Lösung,

    Wichtig noch: was soll passieren, wenn du ein Objekt vom Typ DynamicArray kopieren willst oder mit = zuweisen willst? Am einfachsten ist es erstmal, das mit ... = delete zu verbieten.

    Haette ein unique_ptr dem gegenueber irgendeinen Vorteil, ausser dass man sich den "Aufwand" ne eigene struct/klasse zu erstellen spart?

    Nö, der hat normalerweise einen anderen Zweck.


Anmelden zum Antworten