absturz wegen delete [] im destruktor?



  • ok, klingt logisch. werde die implementierung mal umgestalten.



  • so, habe das ganze mal ueberarbeitet, aber ein paar probleme und fragen sind noch offen:

    - was meinst du mit "per Kopier"?

    - soll das heissen dass ein objekt, wenn es einfach nur deklariert wird, a la:

    "Classname object;"
    

    ,

    auch gleich initialisiert wird? weil das scheint ja so zu sein.

    problem hierbei ist weiterhin, dass ich die eine instanz von CHeightmap als privates Objekt der klasse CMainLoop habe, und es somit in der klassendefinition (.h-file) deklariere, da mehrere methoden von CMainLoop auf das objekt zugreifen muessen. aber wenn die vorige frage stimmt, dann heisst das dass es eben bei der deklaration auch gleich mit dem defaultkonstruktor initialisiert wird. denn wenn ich den wegmache, bruellt der compiler.

    gleichzeitig funktioniert aber folgendes

    CHeightmap heightmap("data\\textures\\hmap.tga");
    

    in einer methode, aber wenn ich das in der klassendefinition mache, meckert der compiler:

    CMainLoop.h:25: invalid data member initialization
    CMainLoop.h:25: (use `=' to initialize static data members)

    aber wenn ich es eben in der klasse definiere und erst in der methode initialisiere, entstehen (wenn ich das jetzt richtig verstanden habe) 2 objekte, und das ist ja eins mehr als erwuenscht.

    was mache ich hier falsch?

    danke nochmal,

    ---loki



  • - was meinst du mit "per Kopier"?

    Vergiss was du von Java kennst. 😃 C++ != Java. Bei C++ ist viel Context-Abhängig, das zu unterschiedlicher Semantik führt. Bsp.:

    void foo(int i)
    {
    }
    

    i ist hier innerhalb von foo eine neu definierte Variable bzw. Objekt. D.h. auch das gleiche Verhalten bei Strings:

    void foo(std::string i)
    {
    }
    

    Ein neues eigenständiges String-Objekt. Also, wenn du foo aufrufst, wird in beiden Beispielen ein neues int und string erzeugt. Die Objekte werden dann kopiert.

    Wenn du das nicht willst, mußt du die Parameter by-Reference definieren:

    void foo(int &i)
    {
    }
    

    Entsprechend auch bei string, siehe Simons2 Post!

    soll das heissen dass ein objekt, wenn es einfach nur deklariert wird, a la:

    Ja, so ist es. Auch hier vergleichbar mit int:

    int i; // neues int-Objekt auf dem Stack instanziert
    std::string s; // neues string-Objekt auf dem Stack instanziert
    float *f; // neues pointer-Objekt auf dem Stack instanziert
    
    s = "hallo"; // s ein Literal zuweisen
    f = new float; // f eine neue float-Adresse zuweisen
    

    Nichts mit new. new ist nur für dynamisch auf dem Heap erzeugte Objekte nötig.



  • ok, danke.... jetzt wird das ganze schon klarer.

    gibt es dann irgendwie eine moeglichkeit, fuer eine klasse ein privates objekt zu deklarieren, ohne es gleichzeitig zu instanzieren, sodass es spaeter in einer methode der klasse instanziert werden kann?



  • Ja, in dem du einfach Pointer benutzt und dann mit new instazierst. Wie gesagt, new ist ja zum dynamischen instanzieren gedacht... dynamisch in dem Sinne, das du es zu jeder Zeit machen kannst.

    class X
    {
        std::string str; // wird umgehend insanziert, bzw. ist ja die Instanz selbst
        std::string *str_ptr; // nur der Pointer, zeigt ins nichts.
    
    public:
        void create()
        {
            str_ptr = new std::string();   // dynamisch erzeugt.
        }
    };
    

    Muß aber kein user defined Typ sein, kann auch ein build-in Typ sein. Also auch float. Das macht in C++ keinen Unterschied, werden alle gleich behandelt.



  • super. vielen dank, hat mir sehr geholfen 🙂



  • Das delete im Destruktor und eine Nullinitialisierung im Konstruktor nicht vergessen. 🙂



  • nur noch eine letzte frage zum thema: nachdem ich alles umgestellt habe funktioniert auch alles super, nur musste ich alle methodenaufrufe von "object.methode()" nach "object->methode()" umstellen. ist das normal, und wenn: warum? denke mir dass das was mit objekt vs. pointer auf objekt zu tun hat, aber blicke nicht ganz durch.



  • Wenn du über einen Pointer zugreifst, benötigst du ->, das ist normal (-> ist eine Kombination aus Dereferenzieren und Member-Zugriff).



  • Es ist auch kein Luxus, sich erst mit if im Destruktor zu vergewissern, ob der zu löschende Zeiger überhaupt existiert (d.h. kein NULL-Zeiger ist!).
    Irgendwie so:

    class X{
    long* ptr;
    
    public:
    ~X(){
    if(ptr)
     delete[] ptr;
    }
    };
    

    Damit geht man auf Nummer sicher, dass man nicht an der Stelle NULL zu löschen versucht.



  • Das ist Käse. Man darf Nullpointer löschen, da passiert nämlich garnix 😉
    EDIT: Insofern ist das überflüssiger Luxus :p


Anmelden zum Antworten