Zeiger frage in OOP



  • Also folgendes...
    ich kann ja folgendes machen:

    Klassenname * object = new Klassenname(...);
    

    ist das äquivalent zu:

    Klassenname k1(...);
    Klassenname * object;
    object = &k1;
    

    Haben objekte die per "new" angelegt werden sonnst noch besonderheiten?



  • Nein, das ist nicht äquivalent, denn im ersten Codestück liegt das Objekt auf dem Heap, im zweiten Codestack auf dem Stack.



  • ist das äquivalent zu ..

    Nein!

    Haben objekte die per "new" angelegt werden sonnst noch besonderheiten?

    Ja, sie sind mit "new" im Freispeicher angelegt und nicht wie beim zweiten Beispiel auf dem Programmstack.



  • knivil schrieb:

    ist das äquivalent zu ..

    Nein!

    Haben objekte die per "new" angelegt werden sonnst noch besonderheiten?

    Ja, sie sind mit "new" im Freispeicher angelegt und nicht wie beim zweiten Beispiel auf dem Programmstack.

    Was heißt das für mich als entwickler?

    Muss ich dann ähnlich wie in C den speicher wieder frei geben?
    Wenn ich in C mit malloc was reserviere muss ich den ja auch mit free();
    wieder frei gaben.

    Habe ich sonnst irgendwelche vorteile oder besondere nachteile mit "new".

    Bzw im mom scheint mir "new" überhaupt keine vorteile zu bringen.
    Kann im fall eines falles ja auch einfach & benutzen?



  • Sqwan schrieb:

    knivil schrieb:

    ist das äquivalent zu ..

    Nein!

    Haben objekte die per "new" angelegt werden sonnst noch besonderheiten?

    Ja, sie sind mit "new" im Freispeicher angelegt und nicht wie beim zweiten Beispiel auf dem Programmstack.

    Was heißt das für mich als entwickler?

    Muss ich dann ähnlich wie in C den speicher wieder frei geben?
    Wenn ich in C mit malloc was reserviere muss ich den ja auch mit free();
    wieder frei gaben.

    Habe ich sonnst irgendwelche vorteile oder besondere nachteile mit "new".

    Bzw im mom scheint mir "new" überhaupt keine vorteile zu bringen.
    Kann im fall eines falles ja auch einfach & benutzen?

    new ist in C++ wie malloc in C
    delete ist in C++ wie in C
    beide solltest du nicht mischen.
    lass am besten malloc und free in C++ weg, gewöhn dich am besten gleich dran.

    Du hast Vorteile bei new/delete wenn du z.B. mit exceptions arbeitest.



  • Sqwan schrieb:

    Was heißt das für mich als entwickler?

    Alles was du mit new allokierst, musst du mit delete freigeben.
    Alles was du mit new[] allokierst, musst du mit delete[] freigeben.
    (Niemals malloc/free mit new/delete mischen)

    Im Gegensatz zu malloc/free berücksichtigt new/delete die C++ Besonderheiten (wie Konstruktor/Destruktor).

    int * a = new int;     // Allokiert mit new
    delete a;              // Freigabe mit delete
    
    int * a = new int[10]; // Allokiert mit new[]
    delete[] a;            // Freigabe mit delete[]
    

    Stackvariablen werden am Ende des Scopes automatisch freigeben, dynamisch allokierte nicht. Für dynamische Speicherstrukturen (z.B. verkettete Listen) ist die dynamische Speicherverwaltung essenziell (Wenn gleich es dafür schon vorgefertigte Klassen gibt).

    Sqwan schrieb:

    Kann im fall eines falles ja auch einfach & benutzen?

    Ich weiß nicht was du hier mit "&" meinst. Meinst du Referenzen (C++), den Adressoperator (C, C++)... In der Regel wird man in einen modernen C++ Programm selten direkt mit Zeigern, und häufiger mit Objekten und Referenzen hantieren.



  • ^^ Eigentlich kann ich aber nur C.
    Hab mir jetzt ein buch geliehen, das heißt:

    C++ Programmierung von Thomas hagemann
    Franzis wird wohl der Verlag sein.

    Leider muss ich sagen, finde ich verdammt viel wieder von dem ich behaupten würde das es C ist.

    Ich hab nicht das gefühl als wäre es besonders hochwertig.

    delete kommt bis weilen noch garnicht drin vor.

    Wie benutze ich das denn? bzw wann. Einfach wenn ich ein Object nicht mehr brauche delete object?

    Bei google find ich dazu recht viel. Und viel anderes:
    unter anderem delete, delete[], free und object->~klasse();

    Der umstieg von C nach Cpp ist schon ziemlich schwer find ich.

    Aber ein vertrautes wort 😃 Exceptions kenne ich aus PHP und Java

    EDIT: Ok... Das wichtigste ist beantwortet.

    Wo brauch ich dann noch objekt->~Klasse(); ?
    Und ja mit & meine ich referenzen.
    Ich kriege ja auch bei new ne referenz.
    Genau wie mit &object;
    Aber der unterschied wurde ja grade erklärt.

    Jetzt bin ich mir garnicht mal so sicher ob mir &object wirklich eine referenz gibt. Wenn ich es in meinem Code benutze habe ich augenscheinlich jedenfalls den gleichen effekt wie mit "new"



  • Sqwan schrieb:

    Wo brauch ich dann noch objekt->~Klasse(); ?

    Das ist eine Frage für die man ein wenig mehr Texten sollte...
    Es lässt sich wesentlich besser aneignen wenn man die Kapitel
    im Buch durchliest. OOP,Zeiger usw..

    Schau mal ob dein Buch in der liste der empfohlenen Bücher hier ist. Hol dir evtl. ein neues Buch dass es besser erklärt.

    Ich habe u.a. "C++ von A bis Z" von Jürgen Wolf, das mMn zu sehr auf C setzt. Da gibt es deutlich bessere C++ Bücher.



  • Sqwan schrieb:

    Wo brauch ich dann noch objekt->~Klasse(); ?

    Das brauchst du sehr selten, wenn du einen Destruktor manuell aufrufen willst.

    Sqwan schrieb:

    Ich kriege ja auch bei new ne referenz.
    Genau wie mit &object;

    Nein, new liefert einen Zeiger. Der Adressoperator auch.

    Sqwan schrieb:

    Jetzt bin ich mir garnicht mal so sicher ob mir &object wirklich eine referenz gibt. Wenn ich es in meinem Code benutze habe ich augenscheinlich jedenfalls den gleichen effekt wie mit "new"

    Nein, hast du nicht. Mit new kontrollierst du die Lebensdauer und bist für die Freigabe verantwortlich. Automatische Objekte werden am Ende des Scopes zerstört, unabhängig davon ob noch irgendwelche Zeiger oder Referenzen darauf verweisen. Diese werden dann eben ungültig.



  • Sqwan schrieb:

    Hab mir jetzt ein buch geliehen...
    Leider muss ich sagen, finde ich verdammt viel wieder von dem ich behaupten würde das es C ist.

    Ich kenne das Buch nicht, aber dein Zweifel deutet an, das es vielleicht nicht wirklich C++, sondern eher C mit Klassen ist (Leider sehr verbreitet). Wenn dein Englisch nicht schlecht ist, solltest du mal Thinking in C++ anschauen (Ist kostenlos verfügbar).

    Sqwan schrieb:

    delete kommt bis weilen noch garnicht drin vor.

    Sofern new (sowie das in der Regel nur in C gebräuchliche malloc/free) bislang auch nicht darin vorkommt, ist alles okay 😉
    Ansonsten hoffe ich das er schon Smartpointer verwendet xD...

    Sqwan schrieb:

    Wie benutze ich das denn? bzw wann. Einfach wenn ich ein Object nicht mehr brauche delete object?

    new/delete sind mit malloc/free zu vergleichen. Sprich: Wenn du ein dynamisch erzeugtes Objekt benötigst (häufig reichen aber Stackvariablen), verwendest du new, und wenn du es nicht mehr brauchst, delete.

    Unter C++ werden aber wie gesagt malloc/free eigentlich nie benötigt (ich kenne zwar durchaus sinnvolle Fälle, habe aber in inzwischen mehr als 10 Jahren C++ Entwicklung noch kein einziges mal malloc/free benötigt - außer eine externe C-Bibliothek hat malloc verwendet, und erwartet das man free aufruft).

    Sqwan schrieb:

    Der Umstieg von C nach Cpp ist schon ziemlich schwer find ich.

    Das Problem ist, das C++ zwar mit C weitgehend abwärtskompatibel ist, die Denkweisen und Programmierung sich aber teilweise grundlegend unterscheiden.

    Sqwan schrieb:

    Wo brauch ich dann noch objekt->~Klasse(); ?

    In der Regel niemals (wie auch malloc/free), es sei den du arbeitest auf sehr niedriger Basis...

    Sqwan schrieb:

    Und ja mit & meine ich referenzen.

    Glaube ich inzwischen nicht mehr, ich glaube man sollte erst einmal hier ein wenig auf das & in seinen verschiedenen Formen eingehen (Da es aus Abwärtskompatibilität mehrere Bedeutungen hat).

    In C++ werden Zeigervariablen üblicherweise nicht als Referenzen bezeichnet, und C++ Referenzen können zwar (eigentlich geht das hier zu weit) intern als Zeiger abgebildet werden, aber das geschieht unter der Haube, ebenso gut können Referenzen teilweise auch gänzlich wegoptimiert werden.

    Also, was ist eine Referenz? Und was unterscheidet sie von einem Zeiger?

    Referenzen sind sogenannte Aliasnamen. Eine Referenz ist effektiv die gleiche Variable, und wird auch genauso eingesetzt:

    // Referenzen (& in der Bedeutung als Referenz)
    int a = 4;
    int & b = a; // b ist ein Aliasname für a: b IST a
    b = 8;       // a hat nun den Wert 8.
    

    Referenzen werden häufig bei Übergaben verwendet, wenn entweder der ursprüngliche Wert geändert werden soll, oder wenn große Objekte übergeben werden, ohne sie zu kopieren (in der Regel in Zusammenhang mit const, falls sie nicht verändert werden sollen):

    // Komplexeres Referenzbeispiel (bei Übergaben)
    #include <iostream>
    
    class A
    {
        /* ... stellvertretend für eine komplexe Klasse ... */
    
        private:
            int b;
    
        public:
            A()
            :   b(0)
            {
            }
    
            void SetB(int b)
            {
                this->b = b; // Ändert Membervariable b
            }
    
            int GetB() const // const bedeutet hier: Methode Ändert nichts am
            {                //   Objektstatus.
                return b;    // Liest Membervariable b aus
            }
            //...
    };
    
    void foo1(A a)
    {
        // a ist eine Kopie, Änderung ist daher lokal
        a.SetB(1);
        std::cout << a.GetB() << std::endl;
    }
    
    void foo2(A & a)
    {
        // a ist eine Referenz, Änderung betrifft Originalobjekt, da die
        //   Referenz a nur ein Aliasname für das Originalobjekt ist - sprich:
        //   a IST das Originalobjekt.
        a.SetB(2);
        std::cout << a.GetB() << std::endl;
    }
    
    void foo3(A const & a) // oder (const A & a) ist gleichbedeutend
    {
        // a.SetB(3); - Geht nicht, da SetB das Objekt ändern würde, a aber
        //   eine konstante Referenz ist. GetB ist wiederum als const markiert
        //   und der Aufruf daher für ein Konstantes Objekt zulässig. a ist
        //   hierbei nicht kopiert wurden und das Originalobjekt - aber nicht
        //   modifizierbar
        std::cout << a.GetB() << std::endl;
    }
    
    int main()
    {
        A a;
        std::cout << a.GetB() << std::endl;
        foo1(a);
        std::cout << a.GetB() << std::endl;
        foo2(a);
        std::cout << a.GetB() << std::endl;
        foo3(a);
        std::cout << a.GetB() << std::endl;
    }
    

    Im wesentlichen Ähneln Referenzübergaben den Zeigern, nur das die Variable wie ein normales Objekt behandelt wird, und keinerlei Dereferenzierung nötig ist.

    WICHTIG: Referenzen haben aber noch ein Unterschied zu Zeigern. Eine Referenz muss auf ein gültiges Objekt verweisen. Sprich: Wenn eine Übergabe optional sein soll (und NULL zulässig), musst du auf Zeiger zurückgreifen, wenn nicht sind Referenzen "sicherer", da sie (wenn jemand nicht gerade absichtlich Schindluder mit ein paar Hacks macht) kein NULL annehmen können, und "natürlicher" zu verwenden sind.

    Übrigens ist auch eine Mischung zulässig, statt einen Doppelzeiger wie es in C nicht unüblich ist, verwende ich lieber eine Zeigerreferenz (*&), da man dann nicht "doppelt" überlegen muss ;p

    Ich kriege ja auch bei new ne referenz.
    Genau wie mit &object;
    

    Weder noch. new liefert einen Zeiger, und "& objekt" ist der aus C bekannte Adressoperator um eine Adresse von einem Objekt zu ermitteln. In diesem Punkt ist die C++ Syntax unschön mehrdeutig.

    cu André



  • asc schrieb:

    In diesem Punkt ist die C++ Syntax unschön mehrdeutig.

    Mehrdeutig ist sie nicht, aber die mehrfach belegten Zeichen können einen am Anfang verwirren. Aber im Grunde ist es nicht schwierig:

    Typ* var;  // Mit Typ: Deklaration eines Zeigers
    *var;      // Unärer Operator: Dereferenzierung
    var1*var2; // Binärer Operator: Multiplikation
    
    Typ& var;  // Mit Typ: Deklaration einer Referenz
    &var;      // Unärer Operator: Adresse
    var1&var2; // Binärer Operator: Bitweises Und
    


  • Ein Zeiger ist im eigentlichen Sinne nichts anderes als eine Referenz, also auch vom Sinn her, das ist eine typische C++-Macke den Unterschied so hervorzuheben, kein anderer Programmierer würde jemals darauf rumreiten wenn jemand einen Zeiger mit Referenz betitelt.

    Ich persönlich benutze auch hauptsächlich Zeiger, da es damit besser sichtlich wird dass hier die Addresse des Originalobjekts geschoben wird und keine Kopie angelegt wird. Obwohl es natürlich Fälle gibt in dem die Anwendung durch Referenzen deutlich verschönt wird, da mach ich auch mal eine Ausnahme... 😉



  • Icematix schrieb:

    Ein Zeiger ist im eigentlichen Sinne nichts anderes als eine Referenz, also auch vom Sinn her, das ist eine typische C++-Macke den Unterschied so hervorzuheben, kein anderer Programmierer würde jemals darauf rumreiten wenn jemand einen Zeiger mit Referenz betitelt.

    Nun ja, es gibt schon ein paar nicht unbedeutende Unterschiede.

    • Zeiger sind Objekttypen, Referenzen nicht
    • Zeiger benötigen explizite Dereferenzierung
    • Zeiger können auf Null zeigen
    • Referenzen sind unveränderlich und müssen bei der Definition initialisiert werden
    • Zeiger erlauben Zeigerarithmetik

    Es ist also nur vernünftig, eine klare Grenze zu ziehen.



  • Icematix schrieb:

    Ein Zeiger ist im eigentlichen Sinne nichts anderes als eine Referenz, also auch vom Sinn her, das ist eine typische C++-Macke den Unterschied so hervorzuheben,...

    Jeder Programmierer sollte mit den Sprachgewohnheiten der Sprache vertraut sein, die er einsetzt. Und es gibt etliche Unterschiede zwischen einer C++ Referenz und einem Zeiger (siehe Nexus). Daher sehe ich es auch nicht als C++ Macke an - jede Sprache hat ihre Eigenheiten, und teilweise einer anderen widersprechenden Bedeutung.



  • -.-


Log in to reply