Zeiger auf Klassenobjekte



  • Hallo, ich habe eine Frage zu Zeigern auf Klassenobjekte.
    Und zwar, ob es nötig ist, die Zeiger auf eine Instanz der Klasse zeigen zu lassen, oder ob man sie direkt benutzen kann. Folgendes Beispiel hat bei mir nämlich funktioniert:

    // datum.cpp
    #include <iostream>
    #include "datum.h"
    
    int main()
    {
      Datum* datum;
      datum->init(21,12,2012);
      datum->print();
    }
    // Methodendefinitionen
    // ...
    

    Dort kann ich mit dem Zeiger direkt die Methoden der Klasse nutzen, ohne
    vorher überhaupt eine Instanz des Objektes erzeugt zu haben...
    Gibt es nun einen Unterschied zu:

    Datum datum;
    Datum* datumPtr = &datum;
    

    ?



  • Ein Zeiger ist eben an keine feste Objektinstanz gebunden und kann halt auch mal an keine gebunden sein. Da bist Du als Entwickler dann dafür zuständig, dass die Aufrufe eben nur auf gültigen Objekten stattfinden.



  • Dein erster Codeschnipsel düfte nicht funktionieren (im Sinne von Segfault).

    Letzterer Code:

    Datum datum;
    Datum* datumPtr = &datum;
    

    müsste funktionieren, da Du die Variable "datum" auf dem Stack ablegst, und dann lediglich nur einen Pointer darauf zeigen lässt.

    Andernfalls müsstest Du den Speicher mit new anfordern (und anschließend mit delete irgendwann einmal wieder freigeben).

    Oder einfach Smart Pointers verwenden (recommended).



  • gnihihihihi schrieb:

    Oder einfach Smart Pointers verwenden (recommended).

    Da spart man sich das freigeben, aber der Pointer kann immernoch ungültig sein.



  • gnihihihihi schrieb:

    Oder einfach Smart Pointers verwenden (recommended).

    Bin noch relativ neu, Smart Pointer kommen erst noch.

    gnihihihihi schrieb:

    Dein erster Codeschnipsel düfte nicht funktionieren (im Sinne von Segfault).

    Das hab ich mir ja auch gedacht, was auf nichts zeigt, kann man auch nicht benutzen. Jedoch funktioniert es genauso wie Möglichkeit Nr. 2. Deshalb meine Frage.
    Ich benutze den MinGW GCC Compiler, falls das nötig ist.



  • Anonymus42 schrieb:

    Das hab ich mir ja auch gedacht, was auf nichts zeigt, kann man auch nicht benutzen.

    Dein Zeiger zeigt nicht auf nichts, er zeigt irgendwo in den Speicher.

    Dein Code erzeugt so genanntes "undefiniertes Verhalten". Das bedeutet, es kann alles passieren, auch, dass das so erst mal läuft, und irgendwann später abstürzt. Du kannst dich also nicht darauf verlassen, dass dieser Code nicht funktioniert.



  • Decimad schrieb:

    Ein Zeiger ist eben an keine feste Objektinstanz gebunden und kann halt auch mal an keine gebunden sein. Da bist Du als Entwickler dann dafür zuständig, dass die Aufrufe eben nur auf gültigen Objekten stattfinden.

    Nimmt er sich dann eine zufällige? Sonst würde es ja nicht funktionieren 😕



  • MFK schrieb:

    Anonymus42 schrieb:

    Das hab ich mir ja auch gedacht, was auf nichts zeigt, kann man auch nicht benutzen.

    Dein Zeiger zeigt nicht auf nichts, er zeigt irgendwo in den Speicher.

    Dein Code erzeugt so genanntes "undefiniertes Verhalten". Das bedeutet, es kann alles passieren, auch, dass das so erst mal läuft, und irgendwann später abstürzt. Du kannst dich also nicht darauf verlassen, dass dieser Code nicht funktioniert.

    Vielen Dank, das wollte ich wissen.



  • Der Zeiger ist ja eigentlich nur eine Speicheradresse, die irgendwo im Speicher liegt. Wenn man ihm nicht zuweist, dann zeigt er auf die Speicheradresse, die sich daraus ergibt, wenn man das, was vorher an der Adresse stand, in der der Zeiger abgelegt ist, als Speicheradresse interpretiert.



  • Initialisiere Deine Pointer (wenn Du sie nicht direkt verwendest) auf nullptr. Dann kannst Du Dir zumindest sicher sein, dass sich der Fehler bei falscher Benutzung bemerkbar macht.



  • Anonymus42 schrieb:

    Nimmt er sich dann eine zufällige? Sonst würde es ja nicht funktionieren 😕

    Ja, der Pointer zeigt auf eine zufällige Addresse. An der Stelle ist aber kein Objekt und deswegen kann man das Verhalten nicht abschätzen. Meistens wird das Programm abstürzen.

    Hier eine lustige, aber sehr gute Erklärung:
    http://www.youtube.com/watch?v=f-pJlnpkLp0



  • Marthog schrieb:

    Anonymus42 schrieb:

    Nimmt er sich dann eine zufällige? Sonst würde es ja nicht funktionieren 😕

    Ja, der Pointer zeigt auf eine zufällige Addresse. An der Stelle ist aber kein Objekt und deswegen kann man das Verhalten nicht abschätzen. Meistens wird das Programm abstürzen.

    Hier eine lustige, aber sehr gute Erklärung:
    http://www.youtube.com/watch?v=f-pJlnpkLp0

    habs mir angesehen, sehr hilfreich 😃



  • Um mal ein bisschen das Vodoo rauszunehmen:
    datum->init ruft die Funktion Datum::init mit den gegebenen Parametern und als versteckten Parameter datum als this-Zeiger auf.
    Der Unterschied zwischen datum1->init und datum2->init ist also, dass die beiden init-Aufrufe unterschiedliche this-Zeiger haben, nämlich einmal datum1 und einmal datum2. Welche Adresse in den Zeigern drin steht ist dabei egal (Das ändert sich aber bei Polymorphie).
    Innerhalb von Datum::init hast du nun einen this-Zeiger der ins Nirvana zeigt. Wenn du den nicht benutzt dann hat das keinen Effekt. Wenn Datum::init static ist dann hat das nie einen Effekt, da es keinen this-Zeiger gibt. Wenn du doch drauf zugreifst kommt es halt drauf an worauf der Zeiger zeigt und ob man dort drauf zugreifen kann. Von zufälligem Inhalt kann eigentlich keine Rede sein, es ist nämlich nicht zufällig, aber es ist undefiniert.
    Es gab mal vor einer Weile die Diskussion, ob man sowas machen kann:

    struct Datum{
    	void init(){}
    };
    Datum *datum = 0;
    datum->init();
    

    Es kam wohl raus, dass das vom Standard her undefiniert ist, obwohl gar keine Dereferenzierung statt findet, demnach wäre dein Code auch undefiniert.


Anmelden zum Antworten