Objectpointer



  • Hier zum Beispiel:

    int& foo()
    {
      int a=42;
      return a;
    }
    


  • Nur zur Klarstellung: Ich bin nicht "Wie oft denn noch?".

    Aus http://www.c-plusplus.net/forum/309901:

    Sone schrieb:

    seriöseantwort schrieb:

    Sone schrieb:

    Bugs entstehen nie durch Referenzen an sich

    Gib mal eine Referenz auf ein lokales Objekt zurück.

    👍 Gutes Beispiel (ehrlich :D)

    In dem Thread hat sich Sone wieder einmal durch seine Unkenntnis (dort in Bezug auf Referenzen) auf sich aufmerksam.

    Aber sein letzter Post übertrifft wirklich alles.

    Sone schrieb:

    Hier in C++ sagen wir, t1 ist die Instanz, obwohl t1 eigentlich eine Referenz auf die Instanz ist. Diese Referenz ist "für immer" an die Instanz gebunden, und Referenzen können niemals nichts referenzieren, d. h. wenn du eine Referenz benutzt dann kannst du dir sicher sein dass die Referenz immer ein gültiges Objekt referenziert - im Gegensatz zu Pointern

    😮



  • Athar schrieb:

    Hier zum Beispiel:

    int& foo()
    {
      int a=42;
      return a;
    }
    

    *bin c++ beginner*
    Wird a nicht sofort zerstört nach dem foo zu ende ist? Also ist die Referenz zu a ungültig nach Funktionsaufruf?
    Edit:
    Habe es gerade gestestet und es geht anscheinend, sehr merkwürdig.

    Zu meiner eigentlichen Fragen.
    Also benutze ich eigentlich nur Instanzen und kümmere mich um con/destructors?



  • kantaki schrieb:

    Habe es gerade gestestet und es geht anscheinend, sehr merkwürdig.

    Klassisches UB ➡ Undefined Behaviour, "es geht" zufällig, aufgrund der Compiler Implementation und den Umständen wie der Code geschrieben ist. Kurz: Es geht nicht, weil es laut Standard nicht gehen darf. Es ist schlicht falscher Code.



  • kantaki schrieb:

    :::
    
    class Test {
    :::
    };
    
    int main() {
       Test t1(100);
       Test *t2 = new (nothrow) Test(100);
       cout << sizeof(t1) << " " << sizeof(t2) << endl; // prints !!!Hello World!!!
       delete t2;
       return 0;
    }
    

    t1 scheint auch ein pointer zu sein, genau so wie t2. Wo genau liegt der unterschied zwischen t1 und t2?

    Nein, wie kommst du darauf? t1 ist kein Zeiger. t1 ist ein Test-Objekt. t2 ist ein Zeiger auf ein Test-Objekt. Das erste Test-Objekt lebt im automatischem Speicher und lebt nur solange, bis die Funktion zu Ende ist, weil die Dinger im automatischen Speicher automatisch weggeräumt werden. Das zweite Test-Objekt lebt im Freispeicher, weil du es mit new angelegt hast. Würdest du dieses Objekt nicht per delete wieder löschen, würde es noch im Speicher hängen, bis das Programm komplett beendet ist. Der Zeiger t2 lebt aber wiederum im automatischen Speicher. Der wird ordnungsgemäß und automatisch weggeräumt. Nur passiert da nicht viel, wenn ein roher Zeiger weggeräumt wird.

    kantaki schrieb:

    Warum muss ich bei t2 manuell den Speicher freigeben wenn ich doch auf den destructor zugreifen kann, oder wird einfach nur der destructor gecalled wenn ich delete auf t2 mache?

    Bitte was? Du musst das Ding manuell wegräumen, weil du es im Freispeicher angelegt hast. Dazu ist der Freispeicher da. Er überlässt dir die Kontrolle über die Lebenszeit von Objekten.



  • delete ruft den destructor auf und gibt den Speicher frei. Ein destructor-Aufruf gibt aber nicht den Speicher des Objektes (von dessen destructor wir sprechen) frei.



  • Test t1;
    Test* t2
    

    t2 ist vom Typ Pointer und ist meist 4 oder 8 Byte gross (compilerabhaengig). Zeiger zeigen fuer gewoehnlich auf etwas. Hier auf ein Objekt, das mit new erzeugt wurde. Alles was mit new erzeugt wurde, muss (sollte) mittels delete geloescht werden. Um das Objekt zu identifizieren wird der Zeiger t2 benutzt. Der Zeiger t2 ist nach dem delete noch genauso vorhanden wie vorher und zeigt immer noch auf die gleiche Stelle. Da ist aber kein Testobjekt mehr.

    Warum muss ich bei t2 manuell den Speicher freigeben wenn ich doch auf den destructor zugreifen kann

    t2 ist ein Zeiger. Der hat keinen Destruktor. Genau wie: eine Hand mag auf ein Flugzeug zeigen, ist deswegen aber noch lange kein Flugzeug.

    Btw. Der Beitrag von Sone ist jetzt nicht so daneben.



  • okay danke, ich dachte c++ würde mir hier impliziert einen pointer geben. Deswegen habe ich sizeof() benutzt. t1 und t2 waren beide 4, also einfach angenommen das beide vom typ pointer sind.



  • knivil schrieb:

    Btw. Der Beitrag von Sone ist jetzt nicht so daneben.

    Also ist t1 eine Referenz?



  • knivil schrieb:

    Btw. Der Beitrag von Sone ist jetzt nicht so daneben.

    Also können Referenzen immer nur gültige Objekte referenzieren?



  • Wie oft denn noch? schrieb:

    knivil schrieb:

    Btw. Der Beitrag von Sone ist jetzt nicht so daneben.

    Also können Referenzen immer nur gültige Objekte referenzieren?

    Du hast es kapiert. 👍

    Swordfish schrieb:

    knivil schrieb:

    Btw. Der Beitrag von Sone ist jetzt nicht so daneben.

    Also ist t1 eine Referenz?

    Für den Compiler macht das null Unterschied.
    P.S.: Ist es natürlich nicht. Aber man kann es als Referenz betrachten, weil t1 intern, genau wie eine Referenz, nur ein konstanter Zeiger mit Syntaxzucker ist, und es eben syntaktisch keinen Unterschied macht.



  • Ich verstehe nicht, wieso Referenzen nur auf gültige Objekte referenzieren können. Eigentlich sind die doch genau wie Zeiger, nur dass gilt, dass bei Definition auch Initialisierung geschehen muss (<- keine Ahnung, ob das jetzt nach Standard streng genug definiert ist).

    Folgende Referenzen auf ungültige Objekte funktionieren doch syntaktisch:

    int* ptr = new int(5);
    int& ref1 = *ptr;
    
    delete ptr; // nun zeigt refl auf kein gültiges Objekt mehr
    

    Zweitens hat t2 doch eine Indirektion, die t1 nicht hat oder nicht? Geschieht Zugriff auf den Stack nicht schneller? Oder begründet sich der schnellere Zugriff darauf, dass der aktuelle Stackbereich eben "näher" im Vergleich zum Freispeicher und garantiert cachelokal ist?



  • Sone schrieb:

    Wie oft denn noch? schrieb:

    Also können Referenzen immer nur gültige Objekte referenzieren?

    Du hast es kapiert. 👍

    Swordfish schrieb:

    Also ist t1 eine Referenz?

    Für den Compiler macht das null Unterschied.
    P.S.: Ist es natürlich nicht. Aber man kann es als Referenz betrachten, weil t1 intern, genau wie eine Referenz, nur ein konstanter Zeiger mit Syntaxzucker ist, und es eben syntaktisch keinen Unterschied macht.

    Sone, wie lernresistent kann man eigentlich sein? Deine Aussagen wurden dermassen widerlegt, dass sie nie mehr auch nur annähernd wahr werden 🙄



  • Sone schrieb:

    Wie oft denn noch? schrieb:

    knivil schrieb:

    Btw. Der Beitrag von Sone ist jetzt nicht so daneben.

    Also können Referenzen immer nur gültige Objekte referenzieren?

    Du hast es kapiert. 👍

    Wie gibt's das dann, dass das Beispiel von Athar kompiliert!?



  • dot schrieb:

    Sone schrieb:

    Wie oft denn noch? schrieb:

    knivil schrieb:

    Btw. Der Beitrag von Sone ist jetzt nicht so daneben.

    Also können Referenzen immer nur gültige Objekte referenzieren?

    Du hast es kapiert. 👍

    Wie gibt's das dann, dass das Beispiel von Athar kompiliert!?

    Ok. Dann eben so: In einem wohldefinierten Programm gibt es nur gültige Referenzen.

    Edit: Na gut, dann kann es in einem wohldefiniertem Programm eben ungültige Referenzen geben. Nach wie vor ist das hier richtig:

    std::string a = "Hello World!"; //a ist intern ein konstanter Zeiger auf einen std::string irgendwo auf dem Stack
    


  • Sone schrieb:

    Nach wie vor ist das hier richtig:

    std::string a = "Hello World!"; //a ist intern ein konstanter Zeiger auf einen std::string irgendwo auf dem Stack
    

    Nein, ist es nicht. In Java hättest du recht, in C++ nicht. a ist wirklich ein std::string und kein Zeiger. Ein Zeiger auf a existiert nicht, auch nicht intern. Sonst würden auch alle Variablen 4 oder 8 Bytes extra Speicher kosten.



  • Hat dieser Sone überhaupt was kapiert? Was stimmt mit ihm nicht? So schlecht kann man sich doch nicht auskennen, und wenn dann hält man wenigstens den Mund.

    @Sone: Wie wäre es wenn du dich mal mit den absoluten Grundlagen von C++ beschäftigst? Und wenn du dies schon einmal getan hast mache es nochmal und wenn es dann immer noch nicht sitzt nochmal usw. Ist halt nicht jeder zum Programmierer geboren, was wohl auf dich zu trifft. Anders kann ich mir die Inkompetenz nicht erklären, oder ist dein Name Jürgen Wolf?



  • Swordfish schrieb:

    knivil schrieb:

    Btw. Der Beitrag von Sone ist jetzt nicht so daneben.

    Also ist t1 eine Referenz?

    Nein :).



  • Vielen, vielen Dank für die Klarstellung, knivil! 👍 😃



  • Nochmal meine 2 cents dazu:

    Ich arbeite mit fremdem Code (bspw. eine externe Lib), und bekomme von einer Methode eine Referenz zurück. Dann gehe ich davon aus, dass diese auch gültig ist - schlicht und einfach deswegen, weil ich eine Referenz nicht auf Gültigkeit überprüfen kann. Natürlich kann es vorkommen, dass da jemand Mist gebaut hat und eine ungültige Referenz liefert. Aber mit der Signatur "Ich gebe eine Referenz zurück" sagt er mit implizit, "und diese Referenz ist gültig.". Wenn ich dagegen einen Pointer bekomme, dass muss ich diesen überprüfen.

    Soweit die Regel, Abweichungen davon müssen in der Methodendokumentation stehen, bspw. "Die zurückgegebene Referenz ist ungültig, solange nicht 'ConnectToDatabase()' aufgerufen wurde."


Anmelden zum Antworten