Gelöst: Warum wird der Destruktor hier aufgerufen? :Gelöst



  • Hallo,

    push_back kopiert nun mal die Objekte in den vector und logischerweise werden dann die Destruktoren der Orginalelemente aufgerufen. Warum ist das bei dir ein Problem. Du musst doch lediglich auch einen CopyKonstruktor für deine Klasse bereitstellen welche ebenfalls bei Bedarf die Counter erhöht.



  • Du musst doch lediglich auch einen CopyKonstruktor für deine Klasse bereitstellen welche ebenfalls bei Bedarf die Counter erhöht.

    Okay, das hört sich schonmal logisch an.
    Ich beschäftige mich ja gerade erst mit dieser ganzen Konstruktor, Destruktor Thematik.
    Bisher bin ich immer ohne "selbst Erstellte" ausgekommen aber mittlerweile, je objektorientierter ich werde, desto mehr Mechanismen muß ich nutzen, damit es alles auch gut funktioniert.

    Dann werde ich mich wohl mal mit den Copy-Construktoren beschäftigen.

    Danke nochmal,
    Gruß,
    DC



  • Nein das ist schon richtig, dass du bei Objektorientierter Programmierung ohne auskommst. Dafür gibt es ja diese implizierten Mechanismen. Nur irgendwo ist halt mal der Anfang, bzw. will man doch ein wenig mehr machen, als nur stupide Objekte zu kopieren.



  • Ja, leider. Je mehr Flexibilität man einbauen möchte, desto komplexer werden die Mechanismen in den Klassen. Dafür sinkt aber zum Glück die Komplexität des restlichen Codes.



  • Wenn du überaus viele "Verwaltungsfunktionen" wie Kopierkonstruktor, Zuweisungsoperator, Destruktor selbst implementierst, machst du etwas falsch. Im Idealfall hast du ein paar wenige Klassen, die Aufgaben wie Speicherverwaltung etc. übernehmen, und in den anderen Klassen reichen dann dank Wertsemantik und RAII die compilergenerierten Funktionen.

    Natürlich muss man gewisse Dinge wie den Zähler irgendwo implementieren. Aber sobald er mehrmals benötigt wird, hat er schon wieder eine eigene Klasse verdient. Grundsätzlich ist die Objektorientierung nicht umso höher, je mehr du ein spezielles Kopierverhalten implementieren musst. Eher im Gegenteil.

    Andererseits ist es auch nicht nötig, alle Klassen mit Wertsemantik auszustatten. Wenn es keinen Sinn macht, eine Klasse zu kopieren, mach Kopierkonstruktor und Zuweisungsoperator privat und ohne Definition. Dann musst du allerdings andere Container (z.B. boost::ptr_vector ) verwenden.



  • Ja, ich möchte ja in diesem Beispiel, daß die Klasse automatisch weiß, wieviel Elemente bestimmter Signatur in ihr enthalten sind.

    Also anstatt jedesmal alle Vector-Elemente nach der Signatur zu scannen um die Zähler von Hand zu setzen, dachte ich mir, soll es die Klasse selbst machen.
    Das geht ja auch wunderbar.
    Als ich aber dann den Destruktor mit dem gegenteiligen Mechanismus ausstattete,
    damit er die Signaturenzähler verringert wenn ein Vector-Element gelöscht wird, bemerkte ich, daß er auch beim Kopieren er Objekte ausgeführt wird.
    Das ich nun auch noch einen CopyConstruktor brauche macht die Sache natürlich wieder etwas komplexer.
    Denn irgendwie klappt es mit dem auch nicht so richtig.

    Ich habe nun folgenden Code:

    #include <iostream>
    #include <vector>
    #include <string>
    
    using namespace std;
    
    class A
    {
    public:
    A(int a)
    {
     testvar=a;
     if (testvar==1) v1++;
     if (testvar==2) v2++;
     if (testvar==3) v3++;
    cout << "Construktor : " << "testvar " << testvar << endl << v1 << endl << v2 << endl << v3 << endl << endl;
    }
    
    A(const A& a)
    {
     if (a.testvar==1) v1++;
     if (a.testvar==2) v2++;
     if (a.testvar==3) v3++;
    cout << "Copy Construktor : " << "testvar " << a.testvar << endl << v1 << endl << v2 << endl << v3 << endl << endl;
    }
    
    ~A()
    {
     if (testvar==1) v1--;
     if (testvar==2) v2--;
     if (testvar==3) v3--;
    cout << "Destruktor : "  << "testvar " << testvar << endl << v1 << endl << v2 << endl << v3 << endl << endl;
    }
    
    int testvar;
    static int v1;
    static int v2;
    static int v3;
    
    };
    
    int A::v1=0;
    int A::v2=0;
    int A::v3=0;
    
    int main()
    {
    
    vector<A>a;
    a.push_back(A(1));
    a.push_back(A(2));
    a.push_back(A(3));
    a.push_back(A(1));
    a.push_back(A(2));
    cout << "---" << endl << A::v1 << endl << A::v2 << endl << A::v3 << endl << endl;
    cout << "erase " << endl;
    a.erase(a.end()-1);
    cout << "---" << endl << A::v1 << endl << A::v2 << endl << A::v3 << endl << endl;
    cout << "ENDE" << endl;
    return 0;
    }
    

    Ich habe nun einen CopyConstruktor beigefügt und er wird auch ausgeführt aber er hat da wieder seltsames Verhalten.
    Mal hat er die korrekten Werte seines Klassenelement-Attributs dann hat er wiederum völlig falsche Werte. Mir fehlt da absolut der Durchblick, warum er nun trotz CopyConstruktor wieder solche Allüren hat.
    (Vielleicht verzichte ich doch lieber auf den Destruktor und erniedrige die Zählvariablen beim Löschen von Hand, aber es muß doch irgendwie gehen)
    Hat da jemand eine Idee? Vielleicht den CopyConstruktor anders definieren?

    Hier die Bildschirm-Ausgabe:

    Construktor : testvar 1
    1
    0
    0

    Copy Construktor : testvar 1
    2
    0
    0

    Destruktor : testvar 1
    1
    0
    0

    Construktor : testvar 2
    1
    1
    0

    Copy Construktor : testvar 2
    1
    2
    0

    Copy Construktor : testvar 0
    1
    2
    0

    Destruktor : testvar 0
    1
    2
    0

    Destruktor : testvar 2
    1
    1
    0

    Construktor : testvar 3
    1
    1
    1

    Copy Construktor : testvar 3
    1
    1
    2

    Copy Construktor : testvar 4082488
    1
    1
    2

    Copy Construktor : testvar 4063608
    1
    1
    2

    Destruktor : testvar 4082488
    1
    1
    2

    Destruktor : testvar 4063608
    1
    1
    2

    Destruktor : testvar 3
    1
    1
    1

    Construktor : testvar 1
    2
    1
    1

    Copy Construktor : testvar 1
    3
    1
    1

    Destruktor : testvar 1
    2
    1
    1

    Construktor : testvar 2
    2
    2
    1

    Copy Construktor : testvar 2
    2
    3
    1

    Copy Construktor : testvar 4082488
    2
    3
    1

    Copy Construktor : testvar 4063608
    2
    3
    1

    Copy Construktor : testvar 1816222830
    2
    3
    1

    Copy Construktor : testvar 1934958700
    2
    3
    1

    Destruktor : testvar 4082488
    2
    3
    1

    Destruktor : testvar 4063608
    2
    3
    1

    Destruktor : testvar 1816222830
    2
    3
    1

    Destruktor : testvar 1934958700
    2
    3
    1

    Destruktor : testvar 2
    2
    2
    1

    ---
    2
    2
    1

    erase
    Destruktor : testvar 1684960544
    2
    2
    1

    ---
    2
    2
    1

    ENDE
    Destruktor : testvar 4082488
    2
    2
    1

    Destruktor : testvar 4063608
    2
    2
    1

    Destruktor : testvar 1836411759
    2
    2
    1

    Destruktor : testvar 1702129253
    2
    2
    1



  • Wie meinem vorherigen Post zu entnehmen ist, gibts auch noch den Zuweisungsoperator, der ebenfalls überladen werden muss.

    Übrigens könntest du deine Codeduplizierung etwas verringern...



  • Nexus schrieb:

    Wie meinem vorherigen Post zu entnehmen ist, gibts auch noch den Zuweisungsoperator, der ebenfalls überladen werden muss.

    Übrigens könntest du deine Codeduplizierung etwas verringern...

    Okay, dann werde ich mal in dieser Richtung weiterforschen. Danke..

    Gruß,
    DC



  • Was deine "Allüren" betrifft, du musst im Copy-Constructor auch testvar kopieren, sonst steht da nur Mist drin.



  • Was deine "Allüren" betrifft, du musst im Copy-Constructor auch testvar kopieren, sonst steht da alles mögliche drin.



  • dein Problem ist, du kopierst dein testvar im Kopier-Konstruktor nicht

    versuch es mal so fürs verständnis. evtl hilft das.

    class A
    {
    public:
    	A(std::string str):testvar(str){std::cout << "CTor: " << testvar << std::endl;} 
    	A(const A& a):testvar(a.testvar+"-Copy"){std::cout << "Copy-CTor: " << testvar << std::endl;}  // die testvar kopieren!
    	~A(){std::cout << "DTor: " << testvar << std::endl;}
    
    std::string testvar;
    };
    

    Dan einfach statt A(1) mit A("1") aufrufen



  • Paul Müller gab mir den entscheidenden Hinweis.

    Oweh.. Da habe ich ja noch erhebliche Defizite was den Umgang mit Konstruktoren angeht.

    A (const A& a)
    {
     testvar = a.testvar;
     if (testvar==1) v1++;
     if (testvar==2) v2++;
     if (testvar==3) v3++;
    cout << "Copy Construktor : " << "testvar " << testvar << endl << v1 << endl << v2 << endl << v3 << endl << endl;
    }
    

    Ich war mittlerweile so verwirrt, daß ich mit a.testvar und testvar durcheinander kam.
    Klar, wenn der CopyConstruktor eine Kopie erstellt, daß dann auch a.testvar ins neue testvar kopiert werden muß.
    Schließlich ist ja a.testvar der Ursprung und nicht das Ziel.
    Und es ist ja auch ein CopyConstruktor der eine Kopie erstellt und die Kopie ist ja nicht a sondern a wurde ja übergeben.
    Jetzt wo ich drüber nachdenke wird es mir sogar super klar.

    Vielen vielen Dank für die gute Unterstützung hier.

    Trotzdem ergibt sich nun die Frage, wenn der CopyConstruktor eine Kopie des Objektes erstellt, warum muß ich dann a.testvar von Hand nach testvar kopieren?
    Und muß ich dann wenn da noch andere Datenstrukturen in der Klasse sind, ALLE von Hand umkopieren?

    Gruß,
    DC



  • So, hab es ausprobiert.

    In der Tat, man muß die anderen Datenstrukturen ebenfalls zum Kopieren angeben.
    Na, dann ist es mir nun klar, warum es nicht funktioniert hat.


Anmelden zum Antworten