Scopes und Destruktor



  • Hallo,
    folgender Code (der auch compiliert):

    #include <cstdio>
    
    class ABC
    {
    protected:
    	bool foo;
    
    public:
    	ABC()
    	{
    		printf("ABC()\n");
    		foo=0;
    	}
    
    	ABC(int a)
    	{
    		printf("ABC(%d)\n", a);
    		foo=1;
    	}
    
    	~ABC()
    	{
    		if (!foo)
    			printf("~ABC()\n");
    		else
    			printf("~ABC(int a)\n");
    	}
    };
    
    int main(int argc, char** argv)
    {
    	ABC a;
    
    	{
    		printf("In block\n");
    		ABC a=ABC(0);
    		printf("End block\n");
    	}
    
    	printf("After block\n");
    }
    

    Was gibt dieses Programm aus:

    ABC()
    In block
    ABC(0)
    End block
    ~ABC(int a)
    After block
    ~ABC()
    

    OK, was will ich damit sagen: dass der erste Konstruktor ausgelöst wird, ist klar. Allerdings nicht, was (und vor allem warum es) dannach passiert:

    ich hätte erwartet, dass wenn ich ABC(0) aufrufe, der entsprechende Konstruktor aufgerufen wird (was der Fall ist: ABC(0)). Allerdings wäre meine Erwartung gewesen, dass bei der Zuweisung a=... im Block der Destruktor des "alten" ABC ausgelöst wird (weil dieser ja mit dem neuen Inhalt ABC(0) überschrieben wird). Es also folgendermaßen aussähe:

    ABC()
    In block
    ABC(0)
    ~ABC()
    ...
    

    Warum ist dies nicht der Fall? Und liege ich richtig damit, dass an der Stelle "after block" a einen undefinierten Zustand hat?

    Grüße
    wolfgke



  • Wenn du Scope auf Deutsch als Sichtbarkeitsraum übersetzt, ist es vielleicht klarer.

    Was hier passiert ist eigentlich sehr simpel: Es wird ein zweites Objekt mit Namen a angelegt. Dieses ist nur in dem aktuellen Sichtbarkeitsraum sichtbar und wird vor dem a aus dem umschließenden Raum bevorzugt. Wäre das nicht so, dann würdest du aufgrund der One-Definition-Rule (dass jedes Objekt /genau/ einmal definiert und damit initialisiert wird) einen Compilerfehler erhalten.

    a hat nach verlassen des lokalen Sichtbarkeitsraumes natürlich einen definierten Zustand, nämlich den von zuvor.



  • Man, ich Schussel. Ich dachte ein Problem in meinem Programm auf dieses Modellbeispiel reduzieren zu können. Dabei habe ich in dem Modellcode diesen Fehler eingebaut, der mich zu falschen Schlussfolgerungen verleitete...

    Sorry. 😞

    Ich werde gleich einen anderen Code basteln, der das Problem, was in meinem Code besteht hoffentlich diesmal wirklich repräsentiert.

    Dennoch danke.



  • Ich habe den Modellcode modifiziert:

    #include <cstdio>
    
    class ABC
    {
    protected:
    	bool foo;
    
    public:
    	ABC()
    	{
    		printf("ABC()\n");
    		foo=0;
    	}
    
    	ABC(int a)
    	{
    		printf("ABC(%d)\n", a);
    		foo=1;
    
    		if (a==1)
    			throw 5;
    	}
    
    	~ABC()
    	{
    		if (!foo)
    			printf("~ABC()\n");
    		else
    			printf("~ABC(int a)\n");
    	}
    };
    
    int main(int argc, char** argv)
    {
    	ABC a;
    
    	try
    	{
    		printf("In block\n");
    		a=ABC(0);
    		printf("End block\n");
    	}
    	catch (int x) {}
    
    	printf("After block\n");
    }
    

    Jetzt entspricht er dem, wie er sein sollte:

    Ausgabe:

    ABC()
    In block
    ABC(0)
    ~ABC(int a)
    End block
    After block
    ~ABC(int a)
    

    Warum wird der Destruktor ~ABC(int a) und nicht ~ABC() aufgerufen? Jetzt repräsentiert es hoffentlich wirklich das Problem.



  • a = ABC(0);
    

    Hier wird op= aufgerufen. Da du ihn nicht explizit definiert hast macht der Kompiler das für dich. Der op= vom Kompiler erstellt eine Flache Kopie, also werden einfach die Membervariablen kopiert.
    ABC(0) erstellt ein temporäres ABC-Objekt, sein Member foo ist true. Demnach wird foo in a auch auf true gesetzt.

    Gruß
    Don06



  • Danke, Don06.

    Jetzt weiß ich die Ursache des Fehlers in meinem Programm (auch wenn ich die Konsequenzen, die dieses Verhalten hat, noch durchdenken muss).


Anmelden zum Antworten