Wo "delete[]" setzten, wenn Array mit return aus Funktion übergeben werden soll + Exception notwendig?



  • Fruchti schrieb:

    double *transrotation (double ar, double br, double cr, double *vector)
    {
           //...
           try
           {
              // Variable nicht lokal im try-Block deklarieren, erst die Zuweisung
              // mit new sollte hier stehen.
              double *rot = new double[3];   //pointer to vector "rot" (X,Y,Z)
           }
           catch (bad_alloc&)
           {
              // So etwas bringt _garnichts_:
              cout << "Error allocating memory." << endl;
              // Wenn man bad_alloc nicht sinnvoll behandeln kann, sollte die
              // Exception auch nicht abgefangen werden. In deinen Fall:
              // Würde die Exception geworfen werden, wäre der anschließende
              // Zugriff vermutlich eine "Access Violation", bzw. undefiniert -
              // das hilft nicht wirklich.
           }
           //...
    }
    

    Imho besser:
    a) Diese Exception nicht abfangen (oder erst "ganz" oben, um dort ein Trace etc. zu machen).
    b) Zeiger mit new allokieren, und anderswo freizugeben ist meiner Meinung nach schlechter Programmierstil. Besser: entweder auf Objekte zur Datenhaltung umschwenken (z.B. std::vector, std::tr1::array) oder mit Smartpointern (z.B. boost::shared_array) arbeiten.

    cu André



  • Sprich, auf meinen Beitrag bezogen, ich lösche nicht (wie von mir immer geglaubt):

    delete[] rot;
    

    irgendwo, sondern schreibe:

    delete[] transrotation;
    

    und damit habe ich automatisch das Problem mit rot geklärt?



  • Fruchti schrieb:

    delete[] transrotation;
    

    Nur wenn dein Zeiger dem du das Ergebnis von deiner Funktion zuweist ebenso wie deine Funktion transrotation heißt. Ich gehe aber eher davon aus das du hier ein Missverständlich hast und dich nochmal mit Zeigerarithmetik näher auseinander setzen solltest...



  • Nein, das hab ich schon verstanden, mich aber zugegebenermaßen sehr schlecht ausgedrückt, natürlich muss ich den entsprechenden Zeiger zu der Funktion (bei mir trans) mit delete verbinden. Sry, dass ich das falsch geschrieben habe.

    Ich werde die Variante erstmal so anwenden, damit das Programm ungefährlich funktioniert und aber trotzdem versuchen mich zu deinen Vorschlägen nochmal einzulesen und das entsprechend zu modifizieren, vielen Dank André. Und Sky0m0sh für die Variante überhaupt.

    Die Exception werd ich dann wohl auch erstmal weglassen. Wenn es auch locker ohne geht, ohne dass Probleme auftauchen, kann ich gut darauf verzichten.



  • Fruchti schrieb:

    Die Exception werd ich dann wohl auch erstmal weglassen. Wenn es auch locker ohne geht, ohne dass Probleme auftauchen, kann ich gut darauf verzichten.

    Sagen wir es so:
    Die Exception kann dir natürlich Probleme bereiten. Aber: Eine Exception sollte man auch nur da fangen, wo man sie auch sinnvoll behandeln kann. Dies kannst du aber in deiner Funktion nicht (Der Speicher ist nicht verfügbar, und die Zugriffe danach machen keinen Sinn wenn man keinen Speicher hat).

    Diese Exception könntest du maximal um den Aufruf und die anschließende Behandlung und Freigabe packen (Sprich: Im Falle der Exception wird die Funktion direkt verlassen und die Behandlung und Freigabe - du hast ja ohnehin keinen gültigen Speicherbereich - übersprungen).

    Zudem gehört bad_alloc zu den Exceptions bei denen man in der Regel ohnehin nicht viel machen kann. Die einzige Strategie die ich kenne ist die, das man am Programmstart einen Speicherbereich alloziert, den man im Falle eines bad_alloc freigibt und dann einen Hinweis das zu wenig Speicher vorhanden ist anzeigt. Bedingt durch den freigegebenen Speicherbereich reicht es vielleicht noch zum Speicher o.ä.

    Eine Exceptionbehandlung erreicht man nicht in dem man einfach ein try/catch hinsetzt. Sondern wenn try/catch: Bitte an den Stellen wo du etwas machen kannst, damit das Programm anschließend geordnet weiterlaufen kann.

    cu André



  • asc schrieb:

    Zudem gehört bad_alloc zu den Exceptions bei denen man in der Regel ohnehin nicht viel machen kann.

    Warum?
    Wenn man durch Nutzereingaben ausgelöst einen viel zu großen Speicherblock allozieren muß, dann heißt das doch nicht unbedingt, daß kein Speicher mehr frei ist. Beispiel Bildverarbeitung: Nutzer gibt viel zu große Bildgröße ein und der Speicher reicht nicht aus. Natürlich kann man in so einem Fall sinnvoll weitermachen, in dem man dem Nutzer die Rückmeldung gibt, daß der Speicher für seine Wunschbildgröße nicht ausreichend ist.



  • ~john schrieb:

    asc schrieb:

    Zudem gehört bad_alloc zu den Exceptions bei denen man in der Regel ohnehin nicht viel machen kann.

    Warum?
    Wenn man durch Nutzereingaben ausgelöst einen viel zu großen Speicherblock allozieren muß, dann heißt das doch nicht unbedingt, daß kein Speicher mehr frei ist. Beispiel Bildverarbeitung: Nutzer gibt viel zu große Bildgröße ein und der Speicher reicht nicht aus. Natürlich kann man in so einem Fall sinnvoll weitermachen, in dem man dem Nutzer die Rückmeldung gibt, daß der Speicher für seine Wunschbildgröße nicht ausreichend ist.

    Da wird dann aber nie bad_alloc ausgelöst, weil du ja (wie man das am besten macht) vorher schaut, ob es überhaupt genug Speicher hat. Wenn aber mal bad_alloc ausgelöst werden sollte, dann kannst du da tatsächlich nicht mehr viel machen. Wie auch ohne Speicher..



  • drakon schrieb:

    Da wird dann aber nie bad_alloc ausgelöst, weil du ja (wie man das am besten macht) vorher schaut, ob es überhaupt genug Speicher hat. Wenn aber mal bad_alloc ausgelöst werden sollte, dann kannst du da tatsächlich nicht mehr viel machen. Wie auch ohne Speicher..

    Wenn eigentlich noch genügend Speicher vorhanden wäre, aber halt kein ausreichend grosser Block, wird doch auch std::bad_alloc geworfen, oder?

    Wie will man überhaupt vorher schauen, ob noch genügend Speicher verfügbar ist?

    Und falls bad_alloc ausgelöst würde, wäre wahrscheinlich wieder ein wenig Speicher frei vom Stack, durch den die Exception fliegt. Das könnte eventuell reichen, um Heap-Speicherplatz wieder freizugeben.



  • Nexus schrieb:

    drakon schrieb:

    Da wird dann aber nie bad_alloc ausgelöst, weil du ja (wie man das am besten macht) vorher schaut, ob es überhaupt genug Speicher hat. Wenn aber mal bad_alloc ausgelöst werden sollte, dann kannst du da tatsächlich nicht mehr viel machen. Wie auch ohne Speicher..

    Wenn eigentlich noch genügend Speicher vorhanden wäre, aber halt kein ausreichend grosser Block, wird doch auch std::bad_alloc geworfen, oder?

    Wie will man überhaupt vorher schauen, ob noch genügend Speicher verfügbar ist?

    Und falls bad_alloc ausgelöst würde, wäre wahrscheinlich wieder ein wenig Speicher frei vom Stack, durch den die Exception fliegt. Das könnte eventuell reichen, um Heap-Speicherplatz wieder freizugeben.

    Würde mal sagen, dass das alles Implementierungsspezifisch ist.
    Der Standard schreibt nur vor, dass ein Fehler bei der Allozierung des Speicher stattgefunden hat. Warum genau das passiert ist kann sehr verschieden sein.
    Auch das mit dem Block muss nicht unbedingt sein. Ich nehme mal an, dass du darauf anspielst, dass du z.B ein grosses Array haben willst,dass wegen Fragmentierung nicht an einem Stück alloziert werden kann. Aber ansonsten genügendn Speicher da wäre. Nun, da könnte das OS ja einiges machen, dass dein Programm da dennoch den Speicher bekommt. Oder (glaube hatten wir sogar schon mal) sogar, dass du ein so exotisches Betriebssystem hast, dass dir den Speicher trotz Fragmentierung beschaffen kann (ohne auräumen zu müssen).

    Vorher schauen würde ich auch mal mit OS-Spezifischen Funktionen. Wenn du das wirklich brauchst..



  • drakon schrieb:

    Da wird dann aber nie bad_alloc ausgelöst, weil du ja (wie man das am besten macht) vorher schaut, ob es überhaupt genug Speicher hat.

    Vorher nachsehen bringt nichts, es gibt keinerlei Garantie, daß das anschließend klappt. So nebenbei, was willst Du da vorher alles nachsehen?
    Z.B. auf einem UNIX kann man den Speicher für Prozesse eingrenzen, so daß zwar massig Speicher im System frei ist, aber man diesen gar nicht allozieren kann. Richtig toll ist das mit parallel laufenden Prozessen, die man nicht unter Kontrolle hat. Wie soll man deren Laufzeitverhalten vorhersagen können?



  • Fruchti schrieb:

    ...

    Ich möchte auch nochmal betonen, dass Du hier versuchst, die Konsequenzen einer schlechten Entscheidung auszubügeln: Solche "Erzeugerfunktionen" verursachen eben genau diese Probleme, weswegen man sie möglichst meiden sollte.
    Ich habe immer noch nicht begriffen, warum Du meinst, sowas zu brauchen... und warum Du keinen Std-Container (vector&Co) verwenden willst: Das Teil kannst Du genauso verwenden wie ein Array und Du bist alle diese Probleme los...

    Gruß,

    Simon2.



  • Simon2 schrieb:

    Fruchti schrieb:

    ...

    Ich möchte auch nochmal betonen, dass Du hier versuchst, die Konsequenzen einer schlechten Entscheidung auszubügeln: Solche "Erzeugerfunktionen" verursachen eben genau diese Probleme, weswegen man sie möglichst meiden sollte.
    Ich habe immer noch nicht begriffen, warum Du meinst, sowas zu brauchen... und warum Du keinen Std-Container (vector&Co) verwenden willst: Das Teil kannst Du genauso verwenden wie ein Array und Du bist alle diese Probleme los...

    Gruß,

    Simon2.

    Es ist ja nicht so, dass ich den Std-Container nicht verwenden will, sondern es verhält sich eher so, dass ich bis dato noch nicht weiß, wie man diesen Container benutzt. Ich versuche mich in diesen Sachverhalt, der neu für mich ist, einfach noch reinzufinden und habe bisher eben versucht das Programm im Rahmen meiner Möglichkeiten und Kenntnisse aufzubauen. 🙂
    (Und war froh, dass es so funktionierte.)

    Aber ich versuche es noch umzubauen und damit zu verbessern.

    Und bei den Exceptions war es ähnlich, ich habe mich einfach versucht im Internet durch viele Beispiele und Tutorials zu lesen, bin bei den Exceptions vorbeigekommen und dachte: prima, probierst du einfach mal aus...
    es ist ja schließlich doch immer so: durch Fehler lernt man. 🙄



  • Es ist ja nicht so, dass ich den Std-Container nicht verwenden will, sondern es verhält sich eher so, dass ich bis dato noch nicht weiß, wie man diesen Container benutzt.

    Die Standardcontainer sind bei weitem einfacher zu benutzen, als irgendwelches Array gefrikel. 😉 Sobald du dich ein wenig mit der Syntax angefreundet hast und weisst, was templates sind ist es eine enorme Erleichterung. Dazu kommt noch, dass, wenn du einen Container kennst praktisch alle anderen auch benutzen kannst. (gibt immer ein paar spezielle Sachen, aber das ist auch trivial).



  • Nur um mal einige Vorteile der STL-Container zu nennen:

    • Bequemes Einfügen und Löschen von Elementen.
    • Einfaches Durchiterieren und Ermitteln der Grösse möglich.
    • Speicherverwaltung wird einem abgenommen; Elemente werden automatisch zerstört, kopiert und zugewiesen, wenn benötigt.
    • Man hat ein Objekt vorliegen, während rohe Arrays oft wie Zeiger gehandhabt werden (z.B. Übergabe an Funktionen).
    • Je nach Anwendung sind andere Datenstrukturen (verkettete Liste, Binärbaum) besser geeignet als lineare Arrays.

    Als Einführung in die Standard Template Library gibt es hier im Forum gerade drei empfehlenswerte Artikel:
    1) Container
    2) Iteratoren und Algorithmen
    3) Hilfsklassen und Erweiterungen



  • Nexus schrieb:

    Nur um mal einige Vorteile der STL-Container zu nennen:

    • Bequemes Einfügen und Löschen von Elementen.
    • Einfaches Durchiterieren und Ermitteln der Grösse möglich.
    • Speicherverwaltung wird einem abgenommen; Elemente werden automatisch zerstört, kopiert und zugewiesen, wenn benötigt.
    • Man hat ein Objekt vorliegen, während rohe Arrays oft wie Zeiger gehandhabt werden (z.B. Übergabe an Funktionen).
    • Je nach Anwendung sind andere Datenstrukturen (verkettete Liste, Binärbaum) besser geeignet als lineare Arrays.

    ...

    • Einige Implementierungen bieten "range checking" - zumindestens an/abschaltbar - an.

    ... denn die Anlage von Arrays ist üblicherweise nur der erste Schritt - danach kommen üblicherweise die Threads "Warum schmiert mein Programm ab?". 😃

    Gruß,

    Simon2.



  • Simon2 schrieb:

    • Einige Implementierungen bieten "range checking" - zumindestens an/abschaltbar - an.

    Das ist sogar bei allen Implementierungen gegeben - wenn Du die Methode at() benutzt. 😃



  • Oder man debuggt halt wie jeder normale Mensch und stösst auf Assertions. 😉



  • Nexus schrieb:

    Oder man debuggt halt wie jeder normale Mensch und stösst auf Assertions. 😉

    😕
    Den Hinweis bekomme ich nicht mehr in den Diskussionszusammenhang: Ist dsas jetzt ein Argument für/gegen die Verwendung von STL-Containern oder at() oder operator[] oder ... ?
    Oder musst das einfach mal gesagt werden ? 😉

    Gruß,

    Simon2.



  • Simon2 schrieb:

    Oder musst das einfach mal gesagt werden ? 😉

    Wohl am ehesten das. 🙂

    Das "normale Mensch" könnte falsch verstanden werden, da hast du Recht. Ich wollte nur darauf hinweisen, dass man gerade so gut im Debug-Modus auf Out-Of-Ranges prüfen kann.



  • Also auch wenn ich bei den letzten Aussagen nicht mehr ganz mitkomme, danke für euer Hilfe! Ich habe es heute geschafft mein Programm vollständig auf vector umzustellen und hab alle Pointer und Arrays rausgeschmissen und er rechnet mir immer noch richtige Werte aus. 🙂

    Ich werde zwar noch viel Übung brauchen, bis ich vollständig dahintergestiegen bin, aber es war ein guter Anfang. Hab auch überall at() benutzt. 🙂
    Ich hoffe damit speichermäßig nicht mehr auf Probleme zu stoßen.


Anmelden zum Antworten