Wo leake ich hier memory? Dynamic array



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

    Gibt es keine Faelle in denen es sinnvoll waere sowas selbst zu implementieren? Was ist denn sonst der Sinn von dem Ganzen, wenn man es nie benutzen soll?

    Sinnvoll. Ja, schon irgendwie. Man sollte mal erlebt haben was Speicherverwaltung bedeutet. Sowas relativ am Anfang eines C++-Kurses zu machen halte ich für Bullshit.
    Container selbst implementieren? Ja klar. Wenn man ganz spezielle Anforderungen hat. Aber auch dann würde man eher nur einen allocator schreiben. Oder man braucht sowas in die Richtung: https://patents.google.com/patent/US8375062B2/en



  • Hast Du den Code schon um den trivialen Rest ergänzt und kommt er durch die Validierung eures tollen Servers?



  • @Swordfish Das werd ich morgen mal ausprobieren, danke dir nochmal fuer die Hilfe und die ganzen Ansaetze die ich noch lernen muss ^^



  • Kein Problem. Der Thread war ein Trauerspiel zum mitansehen. Willst Du denn wirklich C++ lernen?



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

    Kein Problem. Der Thread war ein Trauerspiel zum mitansehen. Willst Du denn wirklich C++ lernen?

    Ja eigentlich schon, aber haben es von der Uni aus jetzt auch erst seit 2 Wochen. Da ist ja klar, dass ich noch einiges vor mir hab



  • Ja nee. Besorg' Dir "Der C++-Programmierer" in der aktuellen Auflage und vergiss ganz schnell ganz viel von dem was Du an der Uni "lernst".
    Talent scheinst Du zu haben bei nur einer Frage zu meinem Code 😉



  • @Swordfish Danke fuer den Tipp, ich werds mir mal anschauen, ich wollte mir eh noch ein Buch dazu holen. Ist leichter als sich nur durch Tutorials und Dokumentationen zu lesen fuer den Anfang



  • Das Hauptproblem mit Tutorials ist daß Du die Qualität als Anfänger nicht einschätzen kannst und Du Dir sehr wahrscheinlich Blödsinn beibringst.
    Da ein Link zu "unserem" Discord: https://discord.gg/5aGDBu2r



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

        double input;
    
        std::cout << "Your values:\n";
        while (std::cout << data_size + 1 << ": ", std::cin >> input) {
            double *tmp = static_cast<double*>(std::realloc(data, (data_size + 1) * sizeof(*data)));
            if (!tmp) {
                std::cerr << "Not enough memory :(\n\n";
                std::free(data);
                return EXIT_FAILURE;
            }
            data = tmp;
            data[data_size] = input;
            ++data_size;
        }
    

    ach so, daraus sollte man eher eine for-loop machen:

        std::cout << "Your values:\n";
        for (double input; std::cout << data_size + 1 << ": ", std::cin >> input; ++data_size) {
            double *tmp = static_cast<double*>(std::realloc(data, (data_size + 1) * sizeof(*data)));
            if (!tmp) {
                std::cerr << "Not enough memory :(\n\n";
                std::free(data);
                return EXIT_FAILURE;
            }
            data = tmp;
            data[data_size] = input;
        }
    

    Hat den Vorteil der engeren Lokalität von input und der hervorragenden Stelle an der data_size inkrementiert wird.



  • @marcel91200 Darf ich fragen welche Uni?



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

    ach so, daraus sollte man eher eine for-loop machen:

        std::cout << "Your values:\n";
        for (double input; std::cout << data_size + 1 << ": ", std::cin >> input; ++data_size) {
            double *tmp = static_cast<double*>(std::realloc(data, (data_size + 1) * sizeof(*data)));
            if (!tmp) {
    ...
    

    Ich würde eher sagen: Man sollte in Schleifenbedingungen keinen , Operator verwenden.



  • @hustbaer Ja, Du hast natürlich völlig recht, ist eine saublöde Angewohnheit 😞



  • Naja, man kann da auch unterschiedlicher Meinung sein. Ich finde es halt doof.



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

    Gibt es keine Faelle in denen es sinnvoll waere sowas selbst zu implementieren? Was ist denn sonst der Sinn von dem Ganzen, wenn man es nie benutzen soll? Also natuerlich spart man sich ne Menge Arbeit und Probleme wenn man es nie benutzt, aber trotzdem eigenartig

    Man darf nicht vergessen, dass das ganze historisch gewachsen ist. Es wurden kaum Bestandteile der Sprache entfernt, so dass fast jeder alter Code übersetzt werden kann. Bei einigen modernen Modesprachen ist das nicht der Fall, da wird nach Belieben die Kompatibilität mit alten Code gebrochen – nicht so bei C++.

    Vor der ersten ISO Norm von C++ war es faktisch unmöglich Programme zu schreiben, die kein new/delete verwendet haben. Mit der ersten ISO Norm (1998) wurden auch die Container zum Teil der Sprache, während sie vorher als STL durch die C++ Community verbreitet wurden. Die letzte von Stroustrup selbst publizierte Version (cfront 3.0) war sehr viel einfacher als das was es heute als ISO Norm gibt. Damals hatte die Sprachdefinition keine 300 Seiten (als Anhang in Die C++ Programmiersprache), mittlerweile ist die ISO Norm mehr als 1600 umfangreich.

    Es gab dann für C++98 ein sehr gutes Einsteigerlehrbuch für modernes C++: Accelerated C++ von Koenig und Moo. Leider haben die beiden Autoren nie eine aktuelle Auflage für C++11 oder neuer publiziert. Was man hier bei den Aufgaben mal wieder sieht: die Intention der Dozenten ist es, lowlevel Speicherverwaltung zu lehren, weil man das einfach mal gemacht haben muss. Aber das passt leider gar nicht mehr zu modernem C++ und würde dort nur in extremen Ausnahmen eingesetzt z.B. wenn man einfängt einen eigenen Container zu schreiben, der dann aber wiederum nicht direkt auf Speicheranforderungen setzen würde, sondern einen Allokator nutzen würde. An dieser Stelle hatte ich einen Allokator gepostet, der die Allokation auf einem NUMA-System simuliert. Man kann daran sehen, wie man im Prinzip einen Allokator zu schreiben hat. Und mein Allokator nutzt für die eigentliche Speicherverwaltung zwar malloc und free, legt aber den Zeiger in einem std::unique_ptr ab, und übergibt diesem bei Konstruktion gleich die free Funktion, damit der std::unique_ptr sie selbst bei Bedarf aufruft.

    Ich habe vor einiger Zeit damit angefangen eine eigene Matrixklasse zu schreiben, die per Allokator Speicher anfordert, aber da das ganze alles andere als trivial ist, ist sie noch nicht fertig und vor allem getestet. D.h. eigene Container zu schreiben ist alles andere als trivial.



  • @hustbaer Nana, passt scho, es IS unübersichtlich und z'sammg'staucht. Geht leserlicher. 👍



  • @marcel91200 auf @hustbaer s Einwand:

    #include <limits>   // std::numeric_limits<>
    #include <cstdlib>  // std::realloc(), std::free(), EXIT_FAILURE
    #include <memory>   // std::make_unique<>()
    #include <iostream> // std::cin, std::cout, std::cerr
    
    bool isPermutation(int *perm, int count)
    {
        auto cmp = std::make_unique<bool[]>(count);
    
        for (int i = 0; i < count; ++i)
            if (perm[i] < 0 || perm[i] >= count)
                return false;
            else cmp[perm[i]] = true;
    
        for (int i = 0; i < count; ++i)
            if (!cmp[i])
                return false;
    
        return true;
    }
    
    bool isSorted(double *data, int dataCount, int *perm)
    {
        if (!isPermutation(perm, dataCount))
            return false;
    
        for (int i = 0; i < dataCount - 1; ++i)
            if (data[perm[i]] > data[perm[i + 1]])
                return false;
    
        return true;
    }
    
    int main()
    {
        double *data = nullptr;
        int data_size = 0;  // nein, eigentlich std::size_t
    
        std::cout << "Your values:\n";
        for (double input; ; ++data_size) {  // 1)
            std::cout << data_size + 1 << ": ";
            if (!(std::cin >> input))
                break;
    
            double *tmp = static_cast<double*>(std::realloc(data, (data_size + 1) * sizeof(*data)));
            if (!tmp) {
                std::cerr << "Not enough memory :(\n\n";
                std::free(data);
                return EXIT_FAILURE;
            }
            data = tmp;
            data[data_size] = input;
        }
    
        if (!data_size) {
            std::cerr << "No input :(\n\n";
            return EXIT_FAILURE;
        }
    
        std::cin.clear();
        std::cin.ignore(std::numeric_limits<std::streamsize>::max(), '\n');
    
        std::cout << "\nYour indices:\n";
        auto indices = std::make_unique<int[]>(data_size);
        for (int i = 0; i < data_size; ++i) {
            std::cout << i + 1 << ": ";
            if (!(std::cin >> indices[i])) {
                std::cerr << "Input error :(\n\n";
                std::free(data);
                return EXIT_FAILURE;
            }
        }
    
        std::free(data);
    }
    

    Kommaoperator ist zwar nice (und important) to know aber man muss nicht übertreiben.

    1) Fehlt bei einer for-loop die Bedingung so wird `true` angenommen. Idiomatische Endlosschleife in C und C++: for (;;) lies: for-ever.


Anmelden zum Antworten