deleteme - wieso funktioniert das nicht?



  • SeppJ schrieb:

    Die Beschreibung hilft immer noch nicht weiter. Was soll "zerstören/löschen" bedeuten? Beschreib mal die Eigenschaften, die sich verändern sollen.

    Das Objekt soll einfach weg sein.
    Gibt's nicht, kenn ich nicht, usw. usf.


  • Mod

    EOP schrieb:

    Gibt's nicht, kenn ich nicht, usw. usf.

    Wie soll sich das äußern? Wer ist das "ich", das das Objekt nicht kennt? Mal angenommen das deleteme im ersten Beitrag wäre solch eine Funktion, wie sähe das von dir gewünschte Programmverhalten aus?

    Destruktoren kennst du, oder?



  • void fun()
    {
       {
          MeineKlasseKlasse x;
       }
       x.Dingsi(); // <- geht net, x ist weg
    }
    

    Ich hab' aber wiedermal den leisen (lauten) Verdacht dass du uns einfach nur verarschen willst.



  • SeppJ schrieb:

    Destruktoren kennst du, oder?

    Also

    void deleteme()
    	{
    		~registered();
    	}
    

    funktioniert schon mal nicht.

    Error 1 error C2675: unary '~' : 'main::registered' does not define this operator or a conversion to a type acceptable to the predefined operator m:\visual studio 2005\projects\testing\test\test\test.cpp 370


  • Mod

    Versuch's mal so:

    this->~registered();
    

    Das ist natürlich höchst gefährlich. Ich hoffe, du weißt, was du tust. Ich habe nämlich nicht den Eindruck. Und du hast immer noch nicht meine Gegenfragen beantwortet, was du überhaupt unter dem Löschen eines Objekts verstehst. Das Ergebnis dieser Aktion könnte eventuell recht enttäuschend sein.



  • SeppJ, es ist 3/4 3 und ich einigermaßen betrunken.
    Geht das als Entschuldigung?


  • Mod

    EOP schrieb:

    SeppJ, es ist 3/4 3 und ich einigermaßen betrunken.
    Geht das als Entschuldigung?

    Don't drink and text!



  • Och Mann, da führt euch EOP an der Nase rum, und dann fühlt sich auch noch der C-Mensch hier berufen ...

    #include <cstring>
    
    class foo
    {
        int a;
    
    public:
        ~foo()
        {
            memset(this,0,sizeof(*this)); /*Dereferenzierung vergessen!*/
        }
    
        void mach_mich_weg()
        {
            delete this;
        }
    };
    
    int main()
    {
        foo*bar = new foo;
        bar->mach_mich_weg();
        return 0;
    }
    

    Wie Jodocus allerdings schon bemerkt hat, ist es wichtig, dass das Objekt auf dem Heap liegt - sonst kracht dir das Ganze mit einem free auf den Stack zusammen (ist auch egal, ob das jetzt C oder C++ ist, bei mir kommt die Fehlermeldung aber von free. C ist C++ immer noch sehr nahe halt). Und das delete sollte die letzte Anweisung in deiner Funktion sein.

    Der Code macht erst den Speicher sauber und gibt ihn dann dem Allokator wieder zurück.
    Aber so spezifisch, wie die Aufgabenstellung aussieht, fällt mir spontan eine Art von Code ein, bei der man das haben will - Kryptocode mit einem selbstgeschriebenen Allokator, wo man sicherstellen will, dass durch eine Sicherheitslücke keine sensiblen Daten rauskommen. Teilweise mache ich das nämlich auch. :p

    Beantwortet das die Frage?



  • Um das ein- für allemal zu sagen:
    Das war nicht als Verarschung oder Trollversuch gedacht (weil ich solche Kindereien grundsätzlich nicht mache - ich mach mich höchstens manchmal über Vollidioten lustig).
    Es war eine ernsthaft gemeinte Sache.
    Wie gesagt, die Idee kam mir nachdem ich "Bitte meinen account löschen" gelesen hatte.

    @dachschaden_off:
    Mit nem Zeiger könnte ich das natürlich auch. Will ich aber nicht.



  • EOP schrieb:

    @dachschaden_off:
    Mit nem Zeiger könnte ich das natürlich auch. Will ich aber nicht.

    Naja, hier ist aber das Problem der Speicherverwaltung, nicht? Ein Objekt liegt entweder auf dem Stack (semi-statisch), oder auf dem Heap (dynamisch), oder in einem Datensegment (komplett-statisch). Wenn die Daten statisch liegen, hast du keine Chance, nachträglich kannst du das Objekt nicht entfernen (außer mit einem perversen Eingriff auf Betriebssystemebene, in dem du die eingebundenen Pages modifizierst, und das ist hässlich und muss nicht mal funktionieren, schon gar nicht, wenn dein Feld in der Segmentmitte auftaucht, dann hast du komplett verloren). Wenn die Daten auf dem Stack liegen, sind ist das Objekt nach dem return wieder weg. Explizit freigeben geht nicht. Das hat einigen bereits das Genick gebrochen, die sich mit alloca schlau vorkamen.

    Bei statischen/semi-statischen Feldern kannst du das Objekt nur nullen, mehr nicht. Und dann hast du halt ein Loch da. Unbenutzt. Aber vorhanden. Und kannst auch wieder reinschreiben, ohne extra Speicher anzufordern. Aber wirklich an das OS freigeben geht nicht. Nur bei Speicher auf dem Heap kannst du nullen und dann wirklich freigeben. Hier kollidiert "wollen" mit "können". Deswegen vermute ich immer noch, dass du hier trollen willst. :p Für so unbefangen in der Speicherverwaltung halte ich dich nicht.



  • Addendum:

    EOP schrieb:

    Objekt x gibt aber immer noch hello() aus.

    Wie lösche ich mich also selbst?

    Hatte ich gar nicht mehr auf dem Kasten, dass du das auch machen wolltest.
    Schlichte Antwort: hello() wirst du immer aufrufen können. Das verlangt meines Wissens die thiscall-Calling Convention. Wie die genau aussieht, ist vom Compiler abhängig - aber überall gilt: er fasst dein Objekt nicht mal an, sondern nur die Adresse auf nicht (mehr) reservierten Speicher. Aber solange du nicht auf this innerhalb von hello() zugreifst, ist ja alles paletti.

    Vielleicht hilft es, sich für diesen Kasus vorzustellen, dass eine Klasse halt auch nur eine Struktur ist wie in C. Die einfach nur Felder, Variablen hat. Und die Methoden werden übersetzt in spezielle Funktionen, die einen Zeiger vom Typen der Klasse (this-Zeiger) übernehmen. Vererbung und Templates mal ganz ignoriert.

    include <cstring>
    #include <iostream>
    
    class foo
    {
        int a;
    
    public:
        void ahoy()
        {
            std::cout << "Ahoy! Dette is mein this-Zeiger: " << this << std::endl;
        }
    };
    
    int main()
    {
            foo*bar = NULL;
            bar->ahoy();
    }
    

    Hier war das Objekt nie initialisiert, und ich kann dennoch ahoy() aufrufen.



  • Dein letzter Beitrag verwirrt mich jetzt ein bißchen. Das sowas funktioniert.

    Und nein, ich werde jetzt nicht bei jedem meiner Beiträge betonen, daß ich nicht trolle.

    Bin in der Theorie eher unbedarft, kann aber funktionierende Programme schreiben.

    EDIT:
    Bin halt ein alter C-Knochen.



  • Intern wird eine Klassenfunktion (Methode) einfach als normale Funktion mit einem zusätzlichen this-Zeiger als Parameter aufgerufen, d.h.

    void foo_ahoy(foo *this_foo)
    {
        std::cout << "Ahoy! Dette is mein this-Zeiger: " << this_foo << std::endl;
    }
    

    Und solange diese Klassenfunktion nicht diesen Zeiger dereferenziert (d.h. auf Klassenmember zugreift) entspricht dies einfach einer globalen bzw. statischen Funktion.

    Trotzdem hätte ich so etwas grundlegendes von dir schon erwartet...

    EOP schrieb:

    kann aber funktionierende Programme schreiben.

    ja klar, das sagen sie alle 😉



  • Th69 schrieb:

    Intern wird eine Klassenfunktion (Methode) einfach als normale Funktion mit einem zusätzlichen this-Zeiger als Parameter aufgerufen

    Kommt drauf an. Wenn man die ahoy Funktion virtual macht gibts einen Segfault. Dann wird nämlich der Pointer schon beim Funktionsaufruf dereferenziert um den vptr zu lesen.



  • Das ist das schlimme daran wenn ein Troll wie Zwerg Bumsti auftaucht - auf einmal meinen dann andere auch dass sie da mitmachen müssten weil es ja ach so lustig ist.



  • hustbaer schrieb:

    Das ist das schlimme daran wenn ein Troll wie Zwerg Bumsti auftaucht - auf einmal meinen dann andere auch dass sie da mitmachen müssten weil es ja ach so lustig ist.

    Dass du mich nicht leiden kannst ist bekannt und OK für mich, aber unterstelle mir bitte nicht irgendwelce Sachen, die jeglicher Grundlage entbehren. Klaro?



  • Ich unterstelle dir, wenn ich der Meinung bin dass du trollst, genau so zu trollen, wie ich es anderen unterstelle, wenn ich der Meinung bin dass sie trollen.

    Wenn dir das nicht passt, dann formuliere deine Fragen so dass man auch davon ausgehen kann dass du es ernst meinst. Was in diesem Thread für mich einfach nicht gegeben ist. Wenn dich das stört, gut, dann erhöhe ich den Leidensdruck bei dir damit vielleicht endlich mal soweit dass du mal darüber nachdenkst.

    Klaro?

    BTW: Ob ich dich nicht leiden kann spielt dabei keine grosse Rolle. Was ich im Übrigen auch so nicht sagen würde. Was im Übrigen jetzt wiederrum eine Unterstellung deinerseits ist. Ist für micht jetzt kein Problem, ich wollte es nur anmerken da du dich im gleichem Atemzug darüber aufregst dass ich dir Dinge unterstelle.

    BTW2: Trollen erfordert im Übrigen keine Absicht. Und wenn du schon selbst zugibst dass du öfters betrunken schreibst und Dinge wie "es ist 3/4 3 und ich einigermaßen betrunken. Geht das als Entschuldigung?" von dir gibst, dann musst du halt damit leben dass behaupte dass du trollst.

    EDIT: Im Übrigen sollte ich nicht SO oft "im Übrigen" im selben Beitrag schreiben wenn ich mich nicht total blamieren will 😞



  • Eigentlich war das Ganze nur eine simple, ernst gemeinte Frage:
    "Kann ein Objekt sich selbst zerstören/ungültig machen?"
    Ich dachte, wenn ich das Objekt nulle müssten auch die Memberfunktionen nicht mehr zugänglich sein, da der Verweis fehlt.

    Daß manche Leute da ne Staatsaffäre draus machen verstehe ich irgendwie nicht. Absolut nicht.



  • Ich nehme an du weisst was UB (undefined behavior) ist? Falls nicht lies es nach.
    Wenn du auf ein Objekt zugreifst das bereits zerstört wurde bekommst du UB.
    UB ist undefined, kann also auch heissen "läuft alles ganz normal als ob das Objekt noch da wäre".
    Wenn du ein Objekt mit memset überschreibst zerstörst du es damit.

    Bei Objekten mit "automatic storage duration" ist das aber problematisch, da so ein Objekt nochmals automatisch zerstört wird. Es wird also der Dtor auf ein Objekt aufgerufen das, da du mit memset drübergebügelt hast, laut Standard bereits als zerstört gilt. Du hast also wieder UB.
    Und zwar mMn. unvermeidlich.
    Man könnte versuchen das Objekt vor dem Ende seines Gültigkeitsbereichs nochmal mit placement new reinzukonstruieren. Aber ob das aus Sicht des Standards dann "OK" ist... weiss nicht. Würde mich nicht darauf verlassen.

    Weiters ist es natürlich ein Fehler ein Objekt mittels memset zu zerstören wenn das korrekte Funktionieren des Programms davon abhängt dass der Dtor aufgerufen wird -- was danach ja nicht mehr erlaubt ist.

    Das selbe gilt für den manuellen Aufruf des Dtors ( this->~T(); wenn ich mich recht erinnere). Auch danach gilt das Objekt als zerstört und darf nicht nochmal zerstört werden.

    Und dass delete auf Objekte mit automatic storage duration nicht erlaubt ist sollte auch klar sein.

    D.h. die einzig sinnvolle Art Objekte mit automatic storage duration zu zerstören ist dafür zu sorgen dass "ihr" Scope verlassen wird. Einen dahingehenden Beitrag hab' ich auch schon geschrieben.
    D.h. die Antwort auf die Frage wie man Objekte mit automatic storage duration korrekt "von innen heraus" zerstört ist: gar nicht, gibt's nicht, geht nicht.
    Als Lösung für Fälle wo man sowas wirklich machen wollen würde fallen mir nur ein:
    * boost::optional o.Ä. verwenden
    * Im Objekt selbst ein "ich wurde zerstört" Flag mitführen
    * Das Objekt doch über [c]new[/c] erzeugen

    EDIT: Unsinn. boost::optional geht nicht "von innen heraus" und bei new hat man ja wieder keine automatic storage duration. Bleibt also nur das Flag. /EDIT

    Ansonsten...

    Bei Objekte die mittels new erzeugt wurden kannst du einfach delete this; sagen.
    Da deine Beispiele aber immer Objekte mit automatic storage duration verwendet haben, ist das wohl nicht die Antwort die du suchst.

    Anm: ich habe jetzt immer "zerstören" geschrieben. Weil ich den Begriff "löschen" für problematisch halte in diesem Zusammenhang. Der manuelle Aufruf des Dtors oder memset zerstören das Objekt, geben aber nicht seinen Speicher frei. delete this; macht dagegen beides.



  • Danke hustbaer, das ist doch endlich mal eine ernsthafte Antwort auf eine ernsthaft gemeinte Frage.


Anmelden zum Antworten