Objekte in Variablen und Ressourcen



  • Ich habe mal wieder eine ziemlich grundsaetzliche Frage, die sich hoffentlich einfach beantworten laesst (konnte aber auf die Schnelle keine brauchbare Erklaerung finden).

    Ich frage mich gerade, wie das in C++ eigentlich mit der Freigabe von Ressourcen gehandhabt wird, wenn man Objekte nicht z.B. mit new/delete explizit ranholt und beseitigt, sondern einfach in Variablen packt.
    Zum Ausprobieren habe ich mir einen kleinen Beispielcode gebastelt...:

    class Test_a
    {
    public:
    	Test_a (int i)
    	{
    		a = i;
    		cout << "Constructor of a=" << a << endl;
    	}
    
    	~Test_a ()
    	{
    		cout << "Destructor of a=" << a << endl;
    	}
    
    private:
    	int a;
    };
    
    int main(int /*argc*/, char **/*argv[]*/)
    {
    	{
    		//little class test...
    		cout << "Create and init bla1... ";
    		Test_a bla1(42);
    		cout << "Create and init bla2... ";
    		Test_a bla2 = Test_a(1337);
    		cout << "overwrite bla1... ";
    		bla1 = Test_a(4711);
    		cout << "Go into scope... " << endl;
    		{
    			cout << "Create and init bla3... ";
    			Test_a bla3(23);
    			cout << "Leave scope... ";
    		}
    		cout << "overwrite bla2... ";
    		bla2 = Test_a(88);
    		cout << "Exit... " << endl;
    	}
    }
    

    Die Frage ist nun: Was passiert eigentlich, wenn ich ein Objekt in so einer Variable einfach mit einem neuen Objekt ueberschreibe? Werden dann die vom alten Objekt reservierten Ressourcen sicher wieder freigegeben? Wie ist dann diese Ausgabe des Codes zu erklaeren? Scheinbar wird der Destructor immer erst nach der Initialisierung des neuen Objekts mit den neu initialisierten Daten ausgefuehrt?

    Create and init bla1... Constructor of a=42
    Create and init bla2... Constructor of a=1337
    overwrite bla1... Constructor of a=4711
    Destructor of a=4711
    Go into scope...
    Create and init bla3... Constructor of a=23
    Leave scope... Destructor of a=23
    overwrite bla2... Constructor of a=88
    Destructor of a=88
    Exit...
    Destructor of a=88
    Destructor of a=4711



  • es ist so:
    wenn du wie in deinem code in zeile 27 und 29 etwas zuweist passiert das hier:
    - es wird ein temporäres anonymes objekt erstellt
    - dieses objekt wird an den zuweisungsoperator (in dem fall automatisch erstellt) übergeben und überschreibt damit den vorherigen zustand deiner variable

    bei solch einfachen beispielen ist alles vom compiler so gewollt, der generiert die zuweisungen und sowas

    bei eigenen grösseren klassen musst du das selbst scheiben und dafür sorgen dass da kein speicher im nirvana verpufft...



  • Ok, danke. Dann werde ich beizeiten noch mit dem Zuweisungsoperator rumspielen.

    Dh. aber, ich kann ansonsten bei verbreiteten Klassen aus Bibliotheken z.B. idR. davon ausgehen, dass die bei solchen Zuweisungen vernuenftig aufraeumen?
    Hintergrund ist, dass ich mit QT in einer Schleife durch Dateinamen iteriere und daraus in jedem Schleifendurchlauf nach dem Muster

    QImage img = QImage(filename);
    

    ein neues QImage-Objekte anlege.



  • Die Zuweisung wird sicherlich keine Leaks erzeugen, andernfalls wäre die Programmierung sehr schlecht. Generell gilt: der Zuweisungsoperator sollte so implementiert sein, dass die allgemeinen Erwartungen an eine Zuweisung erfüllt werden (tiefe Kopie, keine Leaks, kein undefiniertes Verhalten usw. Optimierungen wie Copy-on-Write sind aber möglich, da sich das Verhalten für den Nutzer nicht ändert). Sollte keine vernünftige Implementierung möglich sein, sollte man die Zuweisung verbieten (Zuweisungsoperator private deklarieren).

    Das heißt aber nicht, dass die Zuweisung immer effizient ist. In deinem Fall könnten z.B. sämtliche Pixel ineffizient kopiert werden. Besser ist es, das Objekt direkt mit den Parametern zu konstruieren:

    QImage img(filename);
    

    Technisch gesehen wird übrigens der Kopierkonstruktor aufgerufen und nicht der Zuweisungsoperator, da verhält sich die Sache aber sehr ähnlich.


Anmelden zum Antworten