[gelöst] [Anfänger] Delete von mit new erzeugten Objekten



  • Hallo!

    Ich bin, was die c++ Programmierung betrifft, recht unerfahren und habe sehr wenig Praxis. Ich habe c++ gerade mal ein Semester lang studiert und nutze es in meinem Arbeitsumfeld nur um mal recht einfache dlls zu Programmieren.

    Z.zt. entwickle ich mit Hilfe von gsoap eine dll für einen Aufruf einer SOAP-Schnittstelle. Und wie es jedes mal so ist, verstricke ich mich während der Entwicklungsphase in Kleinigkeiten und Fragen die ich mir selbst nicht sinnvoll beantworten kann (mangels Wissen/Erfahrung).

    So nun das Folgende:
    gsoap erstellt diverse Klassen, die mir den Aufruf der SOAP-Schnittstelle abstrahieren.
    Nun erzeuge ich ein Objekt einer dieser Klassen. Dort hinein packe ich wiederum ein Objekt einer anderen Klasse von gsoap. Und in letzterem Objekt packe ich noch ein paar strings (std::String). Alles wird mit new erzeugt.
    Jetzt müsste ich doch theoretisch auch alles wieder mit delete löschen, was ich zuvor mit new erzeugt habe oder?
    Irgendwie kommt mir das alles so viel und unübersichtlich vor. Macht den Code irgendwie komplizierter und unleserlicher und unleserlicher. Vor allem wenn es verschachtelte Objekte sind deren Referenz ich mir nicht überall merken möchte. Vermutlich bin ich aber auch nur von den üblichen garbage collections verwöhnt...

    Grüße,
    Martin



  • Cosh schrieb:

    Jetzt müsste ich doch theoretisch auch alles wieder mit delete löschen, was ich zuvor mit new erzeugt habe oder?

    Rein theoretisch ja. Es gibt jedoch auch Klassen (ich kenns zumindest aus XML) die ihre Kinder selber freigeben. Für sowas gibt es Dokus und Code Leitinien/ Code Examples.

    Cosh schrieb:

    Irgendwie kommt mir das alles so viel und unübersichtlich vor.

    Nutze Möglichkeiten der Formatierung und Codekommentierung, bilde Abschnitte.

    Cosh schrieb:

    Macht den Code irgendwie komplizierter und unleserlicher und unleserlicher.

    Überleg ob du codeteile nicht zusammenfassen und in funktionen auslagern kannst.

    Cosh schrieb:

    Vor allem wenn es verschachtelte Objekte sind deren Referenz ich mir nicht überall merken möchte.

    Dafür gibt es pointer, typedefs und zur Not Preprocessor #define's

    Cosh schrieb:

    Vermutlich bin ich aber auch nur von den üblichen garbage collections verwöhnt...

    Ich fand Java auch fein bis ich nach dem Studium in die Praxis geworfen wurde. 🙂



  • Ja, du mußt einem new auch ei delete folgen lassen. Aber die Frage ist:

    Ein delete immer einbauen zu müssen, macht den Code nicht unübersichtlicher. Bei uns auf Arbeit programmieren wir Java, und wir müssen immer von den Objekten ein dispose() aufrufen, um aufzuräumen. Das Kind hat nur einen anderen Namen.

    1. Warum benutzt du keine Smartpointer?
    Es gibt in C++ Smartpointer, die autom. ein delete aufrufen, wenn die Objekte nicht mehr referenziert werden. Schau dir mal std::tr1::shared_ptr und std::tr1::weak_ptr an. Wenn du keine aktuelle C++ Umgebung hast, kannst du die gleichen Smartpointer auch in den Boost C++ Libs finden.

    2. Warum benutzt du überhaupt new?
    Wir sind nicht in Java unterwegs! In C++ kann man auch lokale Objekte anlegen, sprich auf dem Stack! Dann braucht man kein new, kein delete und keinen Smartpointer.
    Vorallem bei std::string & Co. ist es 99% der Fälle sinnlos new zu benutzen.

    Siehe hier: http://www.kharchi.eu/wiki/doku.php?id=cpp:std:objects



  • Cosh schrieb:

    Alles wird mit new erzeugt.

    Erste Frage: Ist das wirklich immer nötig, oder reichen teilweise Objekte?

    Cosh schrieb:

    Jetzt müsste ich doch theoretisch auch alles wieder mit delete löschen, was ich zuvor mit new erzeugt habe oder?
    Irgendwie kommt mir das alles so viel und unübersichtlich vor.

    Ja, du musst delete dann auch aufrufen, ob direkt (durch dich) oder indirekt (in dem du mit entsprechenden Hilfskonstrukten arbeitest). Vielleicht solltest du mal ein Blick auf den TR1 oder Boost werfen. Im Speziellen geht es um Smartpointer (TR1, boost) sowie Zeigercontainer (boost).

    Einen einfachen Überblick z.B. über die Smartpointer von boost findest du hier (Kapitel 2).



  • Danke für eure Antworten. Ich denke das wird mir alles etwas weiter helfen. Vor allem die Sachte mit den Objekten auf dem Stack hab ich total vergessen.. Irgendwie kommt das bei mir wirklich aus der Java-Welt, dass ich alles mögliche mit "new" erzeuge. Aber in C++ gab es ja auch die andere Variante ohne new.
    Ja wie gesagt - fehlende Praxis 🙂
    Auch die Sache mit den Smartpointern wird mich sicherlich interessieren.

    Danke!



  • Verwende ein ungeschütztes new so wenig wie möglich. Besonders wenn dein Design komplexer wird, triffst du sonst auf eine Wand von Problemen (bezüglich Exceptionsicherheit, Besitzverhältnisse, einmalige Freigabe).

    Meist kannst du automatische Objekte verwenden, bei besitzenden Zeigern Smart-Pointer. Für mehrere gleiche Objekte gibt es Container (für Polymorphie z.B. extra angefertigte Pointer-Container in Boost).



  • Eine Frage hätte ich da noch...

    Ein vereinfachtes Beispiel was ich hier machen muss:

    Die KlasseB sieht in etwa so aus:

    class KlasseB
    {
    public:
    	std::string *betriebsnummer;
    	std::string *kommunikationsnummer;
    	std::string *kvpsnummer;
    // ...
    

    Da müssen doch also String-Referenzen hinein. Da muss ich doch mit new arbeiten!?

    So sieht meine Verwendung dieser Klasse in etwa an einem konkreten Beispiel aus:

    int meineFkt(struct* config conf) {
       KlasseA a;
    
       if(wasspezielles) {
          KlasseB b;
          b.betriebsnummer = new string(conf->betriebsnummer);
          b.kommunikationsnummer = new string(conf->kommunikationsnummer);
          b.kvpsnummer = new string(conf->kvpsnummer);
          a.blubb = &b;
       }
    
       // schlaue Sachen...
    
       delete a.blubb->betriebsnummer;
       delete a.blubb->kommunikationsnummer;
       delete a.blubb->kvpsnummer;
    }
    

    Ist das so in etwa gängig? Ich brauche all diese Objekte nach dem fkt-Aufruf nicht mehr. Aber da KlasseB einen Pointer auf einen String erwartet fällt mir nichts besseres als das "new" in diesem Fall ein. Ein &string(conf->betriebsnummer) wirft mir eine compilerwarnung aus: "taking address of temporary". Irgendwie klar - aber nichts anderes ist "a.blubb = &b" eigentlich auch und dort meckert er nicht.



  • Da müssen doch also String-Referenzen hinein. Da muss ich doch mit new arbeiten!?

    Nein, überhaupt nicht nötig, sondern nur fehleranfällig!

    Das soll eher so aussehen:

    class KlasseB
    {
    public:
        std::string betriebsnummer;
        std::string kommunikationsnummer;
        std::string kvpsnummer;
    // ...
    

    Ausserdem sollen die Member nicht public sein (auch in Java nicht...).

    Simon



  • Ja, aber die Klassen KlasseA und KlasseB wurden von gsoap erzeugt. Ich benutze sie nur. Ich kann sie nicht verändern. Das ist ja das Problem



  • Cosh schrieb:

    Da müssen doch also String-Referenzen hinein.

    Bitte spreche in C++ nicht von Referenzen, wenn es sich um Zeiger handelt. In Java wird zwar der Begriff Referenz benutzt, in C++ gibt es aber sowohl Zeiger als auch Referenzen. Java arbeitet eigentlich mit etwas das intern eher Zeiger sind, wenn auch mit einer "sicheren" Referenzsyntax (So "sicher" das ich durchaus häufiger in Javaprogrammen Null-Pointer-Exceptions gesehen habe).

    C++ Referenzen sind Aliasnamen für Variablen, sie SIND also (vereinfacht gesprochen) diese Variable. Für die reine Anwendung sind sie einfacher zu bedienen, müssen aber immer auf ein gültiges Objekt verweisen, und können nachträglich auch nicht "umgebogen" werden (Dirty Hacks lasse ich in einer sauberen Programmierung nicht gelten).

    Ja, aber die Klassen KlasseA und KlasseB wurden von gsoap erzeugt.
    

    Da wohl die wenigsten gsoap kennen, kann ich dazu nicht mehr sagen, als das dies scheinbar eine sehr dreckige C++ Umsetzung generiert. Und ja, wenn du dann etwas mit new allokierst, musst du dies auch mit delete aufräumen. Es sei den das berücksichtigt der erzeugte Code auch schon selber. Ohne eine komplette Klasse inklusive Implementierung kann ich das aber nicht sehen - hier solltest du dir die (hoffentlich vorhandene) Hilfe von gsoap anschauen.



  • @Artchi:

    C++ ist wohl eine der wenigen Sprachen, in denen man die meisten Möglichkeiten hat, Objekte zu verwalten.

    Der Einstiegssatz ist wohl etwas misslungen.

    Die meisten C++-Programmierer legen ihre Objekte auf dem Freestore (Freispeicher) an.

    Glaub ich nicht. Wird in keinem Tutorial so gezeigt, wieso sollte das jemand tun?

    Ansonsten ein netter Artikel.

    MfG SideWinder



  • Auch

    Die wenigsten C++-Programmierer wissen, das C++ komplexe Objekte wie native Datentypen behandelt

    ist eine etwas gewagte Aussage. 🙂

    Man bekommt ausserdem etwas den Eindruck, als ob bei

    std::string s("Hallo");
    

    keine dynamische Speicherverwaltung im Spiel wäre und nur der Stack genutzt würde.

    Aber das sind nur Details, die mir gerade aufgefallen sind. Sonst hast du dir echt Mühe gegeben, auch die Illustrationen tragen gut zum Verständnis bei.



  • Okay, danke für alle Antworten. Ich denke meine Frage wurde damit hinreichend beantwortet 🙂

    Schönes Wochenende!


Log in to reply