kostenloser Webspace werbefrei: lima-city


Allokierten Speicher über Zeiger initialisieren

lima-cityForumProgrammiersprachenC/C++ und D

  1. Autor dieses Themas

    primenic

    primenic hat kostenlosen Webspace.

    Hallo,

    es gibt ja die Möglichkeit einen Zeiger mit dem "new"-Schlüsselwort zu initialisieren.
    Wenn ich aber Speicher über malloc allokiere, dann kann ich ja keinen Konstruktor aufrufen, wie es mit "new" der Fall ist.

    FooClass* pPtr = (FooClass*)malloc(sizeof(FooClass));

    so erhalte ich einen Zeiger auf den neu allokierten Speicher.

    Nun meine Frage:
    Wenn ich nun Folgendes mache

    *pPtr = FooClass();


    um den Konstruktor der Klasse FooClass aufzurufen, wird dann nocheinmal ein neuer Speicherbereich allokiert oder wird an das "Zeigerziel" von pPtr eine Instanz der FooClass-klasse gelegt.

    Hoffe ihr wisst, was ich meine? ^^
  2. Diskutiere mit und stelle Fragen: Jetzt kostenlos anmelden!

    lima-city: Gratis werbefreier Webspace für deine eigene Homepage

  3. Hallo Primenic,

    wenn du Folgendes machst:

    *pPtr = FooClass();


    dann wirst Du einen Fehler bekommen, weil FooClass keinen Zeiger zurückgibt.
    In C++ sollte man eigentlich eine der folgenden zwei Möglichkeiten verwenden um ein Objekt zu instanzieren.
    1. Auf dem Stack mit:
    FooClass foo_class;


    2. Auf dem Heap mit:
    FooClass *p = new FooClass()


    Es gibt noch eine dritte Möglichkeit nämlich:
    FooClass *p = &FooClass()

    Beim gcc gibt das nur eine Warnung, aber da man stattdesse ja auch die erste Methode verwenden kann sollte man das lieber lassen.
    Edit 2: Die dritte Möglichkeit sollt man auf keinen Fall machen, weil hier die Instanz von FooClass nur temporär ist, d.h. nach dieser Zeile existiert sie gar nicht mehr.

    Und vielleicht noch ein kleiner Tipp: Wenn man in C++ programmiert sollte man auf malloc(), calloc() usw. soweit möglich verzichten und lieber new/delete verwenden. Da Speicher der mit malloc(),... angelegt wurde mit free() wieder freigegeben werden muss und Speicher der mit new angelegt wurde mit delete, muss man sonst ständig aufpassen, was man verwenden muss.

    Edit:
    Warum willst Du eigentlich speicher mit malloc() anlegen und dann explizit den Konstruktor aufrufen?
    Für sowas musst Du Dir eine Funktion (keine Methode!) schreiben, die genau das macht was der Konstruktor macht, dann geht das wohl auch. Aber das ist wohl eher das was man in C macht.
    Edit 2:
    Wenn Du eine Init-Funktion schreibst, dann wird das auch nicht immer funktionieren, da man ja auch die Virtual Table initialisieren muss und das wird spätestens bei der Verwendung von virtuellen Methoden etwas kompliziert.




    Beitrag zuletzt geändert: 26.12.2010 18:15:56 von darkpandemic
  4. Autor dieses Themas

    primenic

    primenic hat kostenlosen Webspace.

    Die Überlegung war, einen Speichermanager zu schreiben. Da ich mit Direct3D hantiere und dann schonmal Arrays oder andere Ressourcen unter den Tisch fallen, die mit new angelegt wurden. Wenn ich mit einem Speichermanager allokiere und dann die Zeiger auf den allokierten Speicher in einem Array speichere, könnte ich beim beenden des Programms (oder auch währen der Laufzeit) die Ressourcen, die "unter den Tisch gefallen" sind, freigeben.

    PS:
    *pPtr = FooClass();

    Machte bei den Versuchen keine Probleme, weder compiler- noch laufzeitseitig.
  5. Mir scheint, dass Du eigentlich einen Garbage Collector willst, oder?
    Da stellt sich die Frage, woran man erkennt, ob eine Resource noch benötigt wird oder ob sie frei gegeben werden kann.
    Im übrigen kann man ja auch Zeiger auf Objekte die mit new erzeugt wurden in Arrays/Vektoren speichern.

    Und ja, die eine Zeile habe ich falsch interpretiert.

    Edit: Nochmal zurück zur Eingangsfrage. Ich habe es ausprobiert und Du hast wohl recht:
    Mit
    *pPtr = FooClass();

    wird der Konstruktor auf den allozierten Speicherbereich angewendet (da hab' ich mal wieder was interessantes gelernt).
    Allerdings muss man wohl aufpassen, wenn die Objekte nicht flach sind, d.h. wenn im Konstruktor oder an anderer stelle innerhalb des Objekte nochmal Speicher angelegt wird weil mir jetzt beim besten willen nichts dazu einfällt, wie ich den Destrukor auf solche Objekte anwenden kann.

    Beitrag zuletzt geändert: 26.12.2010 20:52:40 von darkpandemic
  6. Autor dieses Themas

    primenic

    primenic hat kostenlosen Webspace.

    darkpandemic schrieb:
    Mir scheint, dass Du eigentlich einen Garbage Collector willst, oder?


    Im Prinzip ja.

    darkpandemic schrieb:
    Da stellt sich die Frage, woran man erkennt, ob eine Resource noch benötigt wird oder ob sie frei gegeben werden kann.


    Hatte mir so gedacht der Funktion des Managers, die dann den Speicher allokiert, eine Art "Lifetime" Parameter zu übergeben. (z.B. "bis zum nächsten Tick" denn meistens sind es ja temporäre Ressourcen, die mal hier, mal da nicht wieder gelöscht werden)

    Aber die Idee die Objekte mit new anzulegen und dann in einem Array zu speichern garnicht schlecht :wink: - glaub dann werd ich das eher so machen. - Danke für den Tipp :thumb:
  7. Wenn Du genau weisst, wieviele Resourcen Du temporär brauchst, dann kannst Du sie am Anfang z.B. mit
    FooClass arr[32];

    anlegen. Und immer, wenn Du weist, dass gerade keine temporären Resourcen benötigt werden kannst Du das Array resetten, d.h. in einen Default-Zustand zurückversetzen. Das bringt einen Haufen Performance, da new (und auch malloc()) sehr aufwändige Operationen sind.
  8. Autor dieses Themas

    primenic

    primenic hat kostenlosen Webspace.

    Danke für den Hinweis... werd mal sehen, was ich draus machen kann :biggrin:

    darkpandemic schrieb:
    Allerdings muss man wohl aufpassen, wenn die Objekte nicht flach sind, d.h. wenn im Konstruktor oder an anderer stelle innerhalb des Objekte nochmal Speicher angelegt wird weil mir jetzt beim besten willen nichts dazu einfällt, wie ich den Destrukor auf solche Objekte anwenden kann.


    Edit 1:
    Anstatt eines Destruktors könnte man auch eine Art Destroy Funtion implementieren, die evtl. Aufräumarbeiten macht.

    Edit 2:
    Kann man nicht einfach
    FooClass* pPtr = (FooClass*)malloc(sizeof(FooClass));
    *pPtr = FooClass();
    
    //und für den Destruktor
    delete pPtr;

    ?

    So weit ich weiß, wird der Destruktor automatisch aufgerufen, wenn man ein delete auf den Zeiger anwendet.
    Würde nurnoch die Frage bleiben, ob auch Folgendes geht und der "richtige" Destruktor aufgerufen wird.

    void *pPtr = malloc(sizeof(FooClass));
    *pPtr = FooClass();
    
    delete pPtr;

    Es handelt sich ja nicht explizit um einen FooClass Zeiger.

    Beitrag zuletzt geändert: 26.12.2010 21:51:34 von primenic
  9. Was willst du denn mit malloc erreichen? (also konkret in den Beispielen -> schreib mal richtige Kommentare)
    Also ersteres ist doch genau dasselbe wie mit new.
    Und das zweite: da wird sicher nicht der richtige Destruktor aufgerufen, weil es nunmal ein nicht gecasteter void Zeiger ist.
    void *pPtr = malloc(sizeof(FooClass));
    FooClass* foo = (FooClass*) pPtr;
    
    delete foo;

    würde den Destruktor richtig aufrufen. Aber da sieht man mal wieder wie sinnvoll das ganze ist.

    Alles was du nach deiner Verwendungsbeschreibung brauchst steht hier schon im Thread. Aber du beharrst komischerweise auf dem malloc und da wüsste ich gern warum. o.o

    Beitrag zuletzt geändert: 26.12.2010 22:34:57 von reimann
  10. Zum Thema Destroy-Funktion:
    Ja soetwas kann man machen, aber das ist halt C-Stil. Das tolle an C++ ist ja eigentlich gerade, dass man Konstruktoren und Destruktoren hat in denen das normalerweise alles automatisch richtig gemacht wird.

    Zum Thema Destuktor:
    Wenn Du den Speicher für das Objekt mittels malloc() anlegst, dann solltest Du diesen auch mittels free() freigeben.
    Es ist schon richtig, dass beim Zerstören eines Objektes mit delete der Destruktor automatisch aufgerufen wird, aber alle Beschreibungen dazu beziehen sich ausschließlich auf Objekte die mit new erzeugt wurden.
    Und eine Möglichkeit den Destruktor aufzurufen, ohne dass der mittels malloc() allozierte Speicherbereich freigegeben wird sehe ich jetzt erst einmal nicht.
    Des weiteren habe ich noch nirgends eine Dokumentation gesehen, in der stand, dass man malloc/calloc/realloc/free mit new/delete mischen kann.
    Das Gegenteil findet sich aber z.B. bei auto_ptr-Typen (übrigens auch ein Weg um soetwas wie Garbage Collection hinzubekommen). Dort darf man explizit kein Zeiger reinstecken die mit malloc/calloc/realloc erzeugt wurden. Und ich gehe mal davon aus, dass die dafür ihre Gründe haben.
  11. darkpandemic schrieb:
    Wenn Du den Speicher für das Objekt mittels malloc() anlegst, dann solltest Du diesen auch mittels free() freigeben.
    Es ist schon richtig, dass beim Zerstören eines Objektes mit delete der Destruktor automatisch aufgerufen wird, aber alle Beschreibungen dazu beziehen sich ausschließlich auf Objekte die mit new erzeugt wurden.


    Naja es geht halt mit einem Typcast kann aber zu undefinierbaren Folgen führen, je nach Compiler bzw. primitive Typen ist es sowieso wurscht (fehlt ja auch der Destruktor). Siehe:
    http://www.codeproject.com/KB/tips/newandmalloc.aspx
    http://bytes.com/topic/c/answers/63382-can-i-use-delete-malloced-items
    http://learningcppisfun.blogspot.com/2007/04/free-new-delete-malloc.html
    Es kann gut gehn muss es aber nicht und kann dir nur unnötig Kopfschmerzen bereiten.

    Eine Destruktormethode aufzurufen ohne den Speicher freizugeben hat auch wenig Sinn. Dafür wäre nicht eine destroy(), sondern eine reset() Methode sehr praktisch, weil eine Wiederverwendung der einzige Sinn ist, warum man es nicht einfach löschen sollte.
    Außerdem betreffen Destruktoren nicht nur delete, sondern auch das Ende des Gültigkeitsbereiches, wenn du mit dem Stack arbeitest. Das sollte man dabei beachten.
  12. So, jetzt habe ich mir noch ein kleines Testprogramm gebastelt, das zeigt, dass das alles mächtig in die Hose geht:
    #include <iostream>
    #include <cstdlib>
    
    using namespace std;
    
    class MyClass
    {
        private:
        int *values;
    
        public:
        MyClass(){ values = new int[10];}
        ~MyClass(){ delete[] values; cout << "Destructor called!" << endl;}
        void setValue(int idx, int value){ values[idx] = value;}
        int getValue(int idx){ return values[idx]; }
    };
    
    int main()
    {
        MyClass *p;
    
        p = (MyClass*)malloc(sizeof(MyClass));
        *p = MyClass();
    
        cout << "Start setting values:" << endl;
        for(int i = 0;i<10;i++)
            p->setValue(i,i);
        cout << "Setting values finished." << endl;
    
        cout << p->getValue(1) << endl;
    
        delete p;
    
        return 0;
    }


    Das erste Problem ist schon die Zeile
    *p = MyClass();

    hier wird nämlich (wie bereits weiter oben erwähnt) das Objekt nur temporär erstellt, d.h. gleich nach dieser Zeile wird das Objekt wieder destruiert, was schon mal zu einer schönen Heap-Corruption führt.
    Und bei
    delete p;

    verabschiedet sich das Programm mit einem Core-Dump.
    Also: Finger weg von malloc()!
  13. Autor dieses Themas

    primenic

    primenic hat kostenlosen Webspace.

    reimann schrieb:
    Alles was du nach deiner Verwendungsbeschreibung brauchst steht hier schon im Thread. Aber du beharrst komischerweise auf dem malloc und da wüsste ich gern warum. o.o


    Ich beharr ja nicht auf malloc - ich wollte halt nur wissen, ob sowas (wie unter Edit2 in meinem letzten Post) funktionieren kann.

    darkpandemic schrieb: So, jetzt habe ich mir noch ein kleines Testprogramm gebastelt, das zeigt, dass das alles mächtig in die Hose geht:
    Das erste Problem ist schon die Zeile
    *p = MyClass();

    hier wird nämlich (wie bereits weiter oben erwähnt) das Objekt nur temporär erstellt, d.h. gleich nach dieser Zeile wird das Objekt wieder destruiert, was schon mal zu einer schönen Heap-Corruption führt.
    Und bei
    delete p;

    verabschiedet sich das Programm mit einem Core-Dump.
    Also: Finger weg von malloc()!


    Hast recht, hab ich heute Früh auch mal versucht.

    Ich werde dann mal auf diese Idee zurückgreifen:
    darkpandemic schrieb: Wenn Du genau weisst, wieviele Resourcen Du temporär brauchst, dann kannst Du sie am Anfang z.B. mit
    FooClass arr[32];

    anlegen. Und immer, wenn Du weist, dass gerade keine temporären Resourcen benötigt werden kannst Du das Array resetten, d.h. in einen Default-Zustand zurückversetzen. Das bringt einen Haufen Performance, da new (und auch malloc()) sehr aufwändige Operationen sind.


    bzw. auf ein Array mit Zeigern, die nur auf temporär benötigte Objekte zeigen.

    reimann schrieb:
    Eine Destruktormethode aufzurufen ohne den Speicher freizugeben hat auch wenig Sinn. Dafür wäre nicht eine destroy(), sondern eine reset() Methode sehr praktisch, weil eine Wiederverwendung der einzige Sinn ist, warum man es nicht einfach löschen sollte.
    Außerdem betreffen Destruktoren nicht nur delete, sondern auch das Ende des Gültigkeitsbereiches, wenn du mit dem Stack arbeitest. Das sollte man dabei beachten.


    Reset wäre in meinem Fall nicht wirklich sinnvoll, da ich ja hauptsächlich Objekte habe, die nur einmal verwendet werden.
  14. Diskutiere mit und stelle Fragen: Jetzt kostenlos anmelden!

    lima-city: Gratis werbefreier Webspace für deine eigene Homepage

Dir gefällt dieses Thema?

Über lima-city

Login zum Webhosting ohne Werbung!