delete this im Konstruktor?



  • Hi,

    ich hab gerade die folgende Anweisung gefunden:

    Foo::Foo(Klasse& Daten)
    {
    	if(!Daten.Geladen())
    	{
    		delete this;
    	}
    //...
    }
    

    Ist sowas zulässig? Macht das überhaupt Sinn? Ich meine, kann dadurch nicht irgendwann mal eine unbehandelte Ausnahme auftreten?



  • das geht wohl nur wenn so ein objekt mit 'new' angelegt wird.


  • Mod

    damit zerstörst du ein objekt, das noch gar nicht existiert (also nein, das ist undefiniertes verhalten). der korekkte ausweg hier ist das werfen einer exception. aber auch dann wird der destruktor nicht ausgeführt - wohl aber der, der subobjekte/basisklassen und es wird auch speicher zurückgegeben sofern dynamisch angefordert.



  • Ich habe das mal im Debugmodus getestet. Das Verhalten ist irgendwie seltsam.

    class Container
    {
    public:
        Container(bool DeleteMe) {if(DeleteMe) delete this;};
        void SetzeWert(int wert) {m_wert = wert;};
        int  HoleWert()          {return m_wert;};
    
    private:
        int m_wert;
    
    };
    //.....
    int main() 
    {
    	Container *Eimer = NULL;
    	Eimer = new Container(true);
    
    	Eimer->SetzeWert(5);           //5 wird gesetzt
    
    	int bla = Eimer->HoleWert();   //5 wird zurückgegebe
    
    	delete Eimer;                  //unbehandelte Ausnahme
    
    	bla = Eimer->HoleWert();
    
            return 0;
    }
    

    Wie in den Kommentaren beschrieben kann ich SetzeWert und HoleWert ohne Probleme aufrufen (obwohl der Speicher freigegeben ist). Ein weiteres delete führt zu einer Ausnahme.

    Bis jetzt dachte ich, das das deferenzieren von ungültigen Zeigern immer zu einer Ausnahme führt. Aber in diesem Fall geht alles gut bis "delete" aufgerufen wird 😮

    Liegt das vieleicht am Visual Studio 6? 😕

    Edit: Kompilierbares Beispiel hinzugefügt



  • Chris++ schrieb:

    Bis jetzt dachte ich, das das deferenzieren von ungültigen Zeigern immer zu einer Ausnahme führt.

    Keine Ahnung wie du darauf kommst. Es führt zu undefiniertem Verhalten.



  • Chris++ schrieb:

    Ich habe das mal im Debugmodus getestet.
    ...
    Bis jetzt dachte ich, das das deferenzieren von ungültigen Zeigern immer zu einer Ausnahme führt.:

    So ist das eben mit undefiniertem Verhalten. Deshalb ist es auch ziemlich sinnlos, da irgendwas zu testen. Du kannst dich auf nichts verlassen, auch nicht darauf, dass es abstürzt.



  • camper schrieb:

    damit zerstörst du ein objekt, das noch gar nicht existiert (also nein, das ist undefiniertes verhalten).

    Bist du dir da sicher, dass es undefniert ist? Das Objekt selbst existiert schon, nur wurde es noch nicht vollständig konstruiert. Undefiniert wäre es für mich nur, wenn der Standard etwas sagt wie "ein dtor darf erst aufgerufen werden, nachdem der ctor aufgerufen wurde", der dtor sich undefiniert verhält oder der Instanzzeiger danach in irgendeiner Form inner- oder ausserhalb der Klasse benutzt wird. Die letzten beiden Punkte kann man aber anhand des geposteten Codes nicht beurteilen.

    Eigentlich kann man auf die Fragen nur eine Antwort geben.

    Macht das überhaupt Sinn?

    Nein. Mir fällt zumindest keine sinnvolle Anwendung ein und halte es schlichtweg für groben Unfug.



  • Hi!

    Was genau willst du egtl mit diesem Unsinn bezwecken???
    Wieso sollte man ein Objekt beim erstellen zerstören wenn du es doch sowiso weiterverwenden willst? Und warum sollte man es überhaupt erst erstellen wenn man es sowiso gleich wieder zerstört? :-S

    grüße


  • Mod

    groovemaster schrieb:

    camper schrieb:

    damit zerstörst du ein objekt, das noch gar nicht existiert (also nein, das ist undefiniertes verhalten).

    Bist du dir da sicher, dass es undefniert ist? Das Objekt selbst existiert schon, nur wurde es noch nicht vollständig konstruiert. Undefiniert wäre es für mich nur, wenn der Standard etwas sagt wie "ein dtor darf erst aufgerufen werden, nachdem der ctor aufgerufen wurde", der dtor sich undefiniert verhält oder der Instanzzeiger danach in irgendeiner Form inner- oder ausserhalb der Klasse benutzt wird. Die letzten beiden Punkte kann man aber anhand des geposteten Codes nicht beurteilen.

    Eigentlich kann man auf die Fragen nur eine Antwort geben.

    Macht das überhaupt Sinn?

    Nein. Mir fällt zumindest keine sinnvolle Anwendung ein und halte es schlichtweg für groben Unfug.

    ohne es nochmal nachgelesen haben - es könnte möglicherweise definiertes verhalten haben, wenn der destruktor trivial ist. ein objekt lebt, nachdem der konstuktor vollständig ausgeführt wurde - der konstruktor selbst stellt ja erst die kohärenz zwischen seinen membern her (die in der initialisierungsliste fertig werden) - und diese invarianten machen aus der ansammlung von member erst ein ganzes objekt (nach meinem verständnis). für diese interpretation spricht ja gerade auch, dass der dtor im fall einer exception eben nicht ausgeführt wird. was passiert bei delete this:
    das objekt (sofern wir annehmen es existiert bereits) wird zerstört - danach wird der konstruktor normal verlassen, ergo haben wir dann ein existierendes zerstörtes objekt :p
    interessant wäre noch, was im falle eines virtuellen geerbten destruktors passiert - ich bin mir jetzt nicht mal sicher, welcher dann ausgeführt wird. nehmen wir an es ist der geerbte. dann haben wir anschließend ein objekt, dessen basis nicht mehr lebt - selbst wenn das kein problem ist: es gibt keine möglichkeit dieses objekt dann später zu zerstören - wieder undefiniertes verhalten. egal wie ich die sache betrachte - es ist und bleibt verwirrend, was ein gutes indiz dafür ist, dass es auch nicht definiert ist 🙂
    es gibt ja nur zwei möglichkeiten für ein objekt: entweder es wird nie (fertig) konstruiert, oder es wird genau einmal konstruiert und danach genau einmal zerstört - obiger fall ist irgendetas anderes.



  • David_pb schrieb:

    Hi!

    Was genau willst du egtl mit diesem Unsinn bezwecken???
    Wieso sollte man ein Objekt beim erstellen zerstören wenn du es doch sowiso weiterverwenden willst? Und warum sollte man es überhaupt erst erstellen wenn man es sowiso gleich wieder zerstört? :-S

    grüße

    Ich will gar nichts damit machen. Ich habs nur in unserem Projekt gefunden 😡
    Prinzipiell verstehe ich warum derjenige das gemacht hat. Er wollte wohl verhindern das ein Objekt erstellt wird sobald gewisse Daten (noch?) nicht geladen wurden.

    Leider gibt new trozdem die Adresse das angelegten Objektes mit und man kann später nicht herausfinden ob es nun gültig ist oder nicht. Das ist also eine Tretmine für's Release.

    danke für eure Antworten



  • Chris++ schrieb:

    Ich will gar nichts damit machen. Ich habs nur in unserem Projekt gefunden 😡
    Prinzipiell verstehe ich warum derjenige das gemacht hat. Er wollte wohl verhindern das ein Objekt erstellt wird sobald gewisse Daten (noch?) nicht geladen wurden.

    Für genau sowas gibt es Exceptions, vielleicht solltet ihr die bei Euch mal einführen :p



  • so gar das geht

    class Lustig {
            private:
                    long a;
    	public:
    		void print() {
    			cout << "Hallo" << endl;
    		};		
    };
    
    Lustig *test = NULL;
    
    int main(int argc, char *argv[]) {
    	test->print();
    }
    

  • Mod

    KingOfTheBlueMouse schrieb:

    so gar das geht

    was bedeutet "geht" bei dir?



  • Chris++ schrieb:

    David_pb schrieb:

    Hi!

    Was genau willst du egtl mit diesem Unsinn bezwecken???
    Wieso sollte man ein Objekt beim erstellen zerstören wenn du es doch sowiso weiterverwenden willst? Und warum sollte man es überhaupt erst erstellen wenn man es sowiso gleich wieder zerstört? :-S

    grüße

    Ich will gar nichts damit machen. Ich habs nur in unserem Projekt gefunden 😡
    Prinzipiell verstehe ich warum derjenige das gemacht hat. Er wollte wohl verhindern das ein Objekt erstellt wird sobald gewisse Daten (noch?) nicht geladen wurden.

    Leider gibt new trozdem die Adresse das angelegten Objektes mit und man kann später nicht herausfinden ob es nun gültig ist oder nicht. Das ist also eine Tretmine für's Release.

    danke für eure Antworten

    Wow, das nenn ich mal schlechten Programmierstil... Sry, aber wer kommt denn auf so bescheuerte Gedanken? 😮

    grüße



  • es wird "hallo" aus gegeben
    und alles laüft normal


  • Mod

    David_pb schrieb:

    Wow, das nenn ich mal schlechten Programmierstil... Sry, aber wer kommt denn auf so bescheuerte Gedanken? 😮

    grüße

    also völlig bescheuert ist das ja nun nicht - nur nicht konsequent zu ende gedacht.

    KingOfTheBlueMouse schrieb:

    es wird "hallo" aus gegeben
    und alles laüft normal

    vielleicht. vielleicht auch nicht - besonders bei vollmond. die eigenheiten einer bestimmten implementation (selbst wenn das bei den meisten compilern so sein sollte) interessieren in diesem forum nur bedingt. was hat das mit dem topic zu tun?



  • ich wollte damit nur anmerken das man sich in c/c++ selbst um den speicher kümmern muss

    das beispiel von mir geht weil ich auf kein speicher zugreife hat also eigentlich garnichts hier mit zu tun 😃



  • David_pb schrieb:

    Chris++ schrieb:

    David_pb schrieb:

    Hi!

    Was genau willst du egtl mit diesem Unsinn bezwecken???
    Wieso sollte man ein Objekt beim erstellen zerstören wenn du es doch sowiso weiterverwenden willst? Und warum sollte man es überhaupt erst erstellen wenn man es sowiso gleich wieder zerstört? :-S

    grüße

    Ich will gar nichts damit machen. Ich habs nur in unserem Projekt gefunden 😡
    Prinzipiell verstehe ich warum derjenige das gemacht hat. Er wollte wohl verhindern das ein Objekt erstellt wird sobald gewisse Daten (noch?) nicht geladen wurden.

    Leider gibt new trozdem die Adresse das angelegten Objektes mit und man kann später nicht herausfinden ob es nun gültig ist oder nicht. Das ist also eine Tretmine für's Release.

    danke für eure Antworten

    Wow, das nenn ich mal schlechten Programmierstil... Sry, aber wer kommt denn auf so bescheuerte Gedanken? 😮

    grüße

    Keine Ahnung. Ich weis nicht wer das geschrieben hat. Ich finde auch das es sinnvoller ist dieses "Daten.Geladen" vorher abzufragen und dann erst ein Objekt zu erstellen ...



  • camper schrieb:

    das objekt (sofern wir annehmen es existiert bereits) wird zerstört - danach wird der konstruktor normal verlassen, ergo haben wir dann ein existierendes zerstörtes objekt :p

    Ja, das meinte ich auch mit

    Undefiniert wäre es für mich nur, wenn [...] der Instanzzeiger danach in irgendeiner Form inner- oder ausserhalb der Klasse benutzt wird.

    Das Objekt wurde zerstört, auch wenn es für den Client so aussieht, als wenn es nach new gerade erzeugt wurde. Ein nachfolgender Zugriff auf das Objekt führt somit unweigerlich zu UB.

    camper schrieb:

    interessant wäre noch, was im falle eines virtuellen geerbten destruktors passiert - ich bin mir jetzt nicht mal sicher, welcher dann ausgeführt wird. nehmen wir an es ist der geerbte. dann haben wir anschließend ein objekt, dessen basis nicht mehr lebt - selbst wenn das kein problem ist: es gibt keine möglichkeit dieses objekt dann später zu zerstören

    Was ja auch nicht nötig wäre, es wurde ja bereits komplett zerstört.

    KingOfTheBlueMouse schrieb:

    es wird "hallo" aus gegeben
    und alles laüft normal

    Undefiniertes Verhalten schliesst aber auch den Fall ein, dass alles "normal" läuft. 😉 Und wie camper schon sagte, beim nächsten Vollmond kann das ganz anders aussehen.

    Chris++ schrieb:

    Ich will gar nichts damit machen. Ich habs nur in unserem Projekt gefunden 😡
    Prinzipiell verstehe ich warum derjenige das gemacht hat. Er wollte wohl verhindern das ein Objekt erstellt wird sobald gewisse Daten (noch?) nicht geladen wurden.

    Dann kannst du ihm ja jetzt zeigen, wie man's richtig macht. 😃


  • Mod

    groovemaster schrieb:

    camper schrieb:

    interessant wäre noch, was im falle eines virtuellen geerbten destruktors passiert - ich bin mir jetzt nicht mal sicher, welcher dann ausgeführt wird. nehmen wir an es ist der geerbte. dann haben wir anschließend ein objekt, dessen basis nicht mehr lebt - selbst wenn das kein problem ist: es gibt keine möglichkeit dieses objekt dann später zu zerstören

    Was ja auch nicht nötig wäre, es wurde ja bereits komplett zerstört.

    nur die basis. der "most-derived"-konstruktor wurde danach noch normal beendet - folglich existiert da immer noch etwas - hohles :p


Anmelden zum Antworten