delete eines Objekts auf dem Stack



  • Hallo,

    folgendes Problem:

    void foo(double my_double)
    {
    	double *ptr = &my_double;
    	delete ptr; // Fehler: _block_type_is_valid(phead- nblockuse)
    }
    
    int _tmain(int argc, _TCHAR* argv[])
    {
    	double *ptr = new double(1.2);
    	foo(*reinterpret_cast<double*>(&ptr));
    }
    

    Das Problem ist ja dass ich hier versuche delete auf ein Objekt anzuwenden, welches auf dem Stack liegt. Aber eigentlich liegt das double ja auf dem Heap, wegen dem new. Wie erkläre ich dem Compiler also, dass die Adresse eben doch auf dem Heap und nicht auf dem Stack liegt?



  • Nein, es liegt auf dem Stack. Du benutzt call-by-value, also wird der Wert vom Heap-Speicher auf den Stack gelegt, den du da versucht zu deleten. Deine ganzen Casts da sind vollkommen sinnlos.

    Sieht alles sehr krank aus. Was hast du wirklich vor?



  • Du übergibst doch eine Kopie von dem double. Wenn, dann musst du einen double* übergeben, das wär dann auch weniger irritierend.



  • Jodocus schrieb:

    Nein, es liegt auf dem Stack. Du benutzt call-by-value, also wird der Wert vom Heap-Speicher auf den Stack gelegt, den du da versucht zu deleten. Deine ganzen Casts da sind vollkommen sinnlos.

    Sieht alles sehr krank aus. Was hast du wirklich vor?

    Mechanics schrieb:

    Du übergibst doch eine Kopie von dem double. Wenn, dann musst du einen double* übergeben, das wär dann auch weniger irritierend.

    Ich weiß dass die casts in diesem Minimal-Beispiel sinnlos erscheinen, aber ich brauche das so.

    Die Sache ist die dass ich einen Wrapper in C++ schreibe für ein Programm dass intern das Aufrufen von (speziell dafür kompilierten) C++ Funktionen erlaubt.

    Diese C++ Funktionen können aber nur primitive Werte als Parameter nehmen und zurückgeben. Problem ist jetzt, dass ich mit Klassen arbeiten will(muss), ich jedeoch keine Klasseninstanz zurückgeben kann (da nicht primitiv).

    Mein Trick also: Ich erstelle eine Klasseninstanz auf dem Heap per new und caste sie in ein double, welches ich zurückgeben darf. Dann benutze ich diese Instanz in einer weiteren Funktion indem ich den gespeicherten double (als Wert!) übergebe und wieder in mein Objekt zurückcaste.

    Das klappt auch alles schon. Nur beim löschen happerts noch (ich will die ganzen Instanzen ja auch wieder loswerden können). Das wird durch mein Minimalbeispiel simmuliert.



  • Der Compiler weiß nicht dass das double auf dem stack liegt, das Laufzeitsystem hat gesagt dass dein delete falsch ist und es hat recht.
    Du holst dir ein double * per new. Dann tust du so als wäre der double pointer ein double und übergibst es der Funktion. Diese ruft delete mit der Adresse des doubles auf das eigentlich ein double * ist. Ich meine hier ist dein Fehler: Du löscht nicht das double was ein double * ist sondern die Adresse der Stackvariablen.

    void foo(double my_double)
    {
    	double *ptr = *reinterpret_cast<double **>(&my_double);
    	cout << "Nachher: " << ptr << '\n';
    	delete ptr;
    }
    
    int _tmain(int argc, _TCHAR* argv[])
    {
    	double *ptr = new double(1.2);
    	cout << "Vorher: " << ptr << '\n';
    	foo(*reinterpret_cast<double*>(&ptr));
    }
    

    Das könnte ausdrücken was du willst. Auf einem 32-Bit-System könntest du Glück haben dass ein double die 32-Bit-Adresse verlustfrei speichern kann und es nicht abstürzt. Wenn vorher == nachher, dann funktioniert das, ansonsten nicht. Und mit "funktioniert" meine ich dass das Undefined Behavior tut was du möchtest.



  • nwp3 schrieb:

    Das könnte ausdrücken was du willst. Auf einem 32-Bit-System könntest du Glück haben dass ein double die 32-Bit-Adresse verlustfrei speichern kann und es nicht abstürzt. Wenn vorher == nachher, dann funktioniert das, ansonsten nicht. Und mit "funktioniert" meine ich dass das Undefined Behavior tut was du möchtest.

    Ok, das funktioniert schonmal (vorher == nachher), aber das ist jetzt also UB? Kann man das irgendwie vermeiden, also dass es immer klappt?



  • Ja, call by reference.



  • Aber wie soll ich das machen, das Programm für das ich den Wrapper schreibe kennt gar keine Referenzen. In der C++ Schnittstelle kann ich mir nur einen pointer auf eine Kopie des übergebenen Wertes holen, daher muss ich die Adresse in dem Wert des doubles codieren.



  • Wieso ersetzt du das double nicht einfach mit einem double *?



  • nwp3 schrieb:

    Wieso ersetzt du das double nicht einfach mit einem double *?

    Wie gesagt, das kann ich nicht. Ich kann nur doubles übergeben und zurückgeben, sonst nichts. Ich muss also aus dem double irgendwie einen validen pointer auf mein Ursprungsobjekt zurückcasten.



  • Kannst du nicht mit ints und handles arbeiten? Ich würds noch sauberer finden, wenn der Parameter ein Handle ist.



  • 1. Warum willst du überhaupt den Pointer dort löschen?
    ggf. gibt es im Code-Fluss eine besser Stelle?

    2. Es gibt doch sicherlich die Möglichkeit globale Variablen zu benutzen?

    std::map<double, yourType*> AllYourPointers;
    

    Dann ist die double Variable eben der Index, dann ist call by value auch egal.



  • double als key einer map ist eine schlechte Idee. Rundungsfehler können unvorhersehbare Folgen haben.



  • void *alloca(size_t size);
    

    dann musst du ihn nicht freigeben....



  • Mechanics schrieb:

    Kannst du nicht mit ints und handles arbeiten? Ich würds noch sauberer finden, wenn der Parameter ein Handle ist.

    ints würde auch gehen, aber das Prinzip würde ja das gleiche bleiben, oder?

    nurf schrieb:

    2. Es gibt doch sicherlich die Möglichkeit globale Variablen zu benutzen?

    std::map<double, yourType*> AllYourPointers;
    

    Dann ist die double Variable eben der Index, dann ist call by value auch egal.

    Nee, gibts so leider nicht, zumindest nicht über verschiedene Funktionen hinaus. Eine globale Variable kann ich zwar schon anlegen, aber nur innerhalb eines Moduls...

    HelloWorldFan schrieb:

    void *alloca(size_t size);
    

    dann musst du ihn nicht freigeben....

    Aber ich will ja wieder freigeben können.



  • happystudent schrieb:

    ints würde auch gehen, aber das Prinzip würde ja das gleiche bleiben, oder?

    Ich würd eben keine Zeiger übergeben, sondern handles. Könnte z.B. so ausschauen wie bei nurf, also mit einer map<int, object>. In deiner Funktion brauchst du dann eine Möglichkeit, über das Handle an das Objekt zu kommen. Kann vielleicht eine globale Zugriffsfunktion sein.



  • happystudent schrieb:

    Mechanics schrieb:

    Kannst du nicht mit ints und handles arbeiten? Ich würds noch sauberer finden, wenn der Parameter ein Handle ist.

    ints würde auch gehen, aber das Prinzip würde ja das gleiche bleiben, oder..

    ich würde in dem Fall ein uint64 nehmen und die Adresse damit so übergeben wie NWP3 es bei dem double machst. Ich sehe darin dann auch ein problem bei einer anwendung auf einem 32 bit System..


Log in to reply