Pointer vs Referenzen



  • Hi

    Ich bin noch ein ziemlicher Anfänger was Programmierung anbelangt, und bin auf ein Problem gestoßen.

    Die Vorteile von Referenzen sind mir klar, es wird kein zusätzlicher Speicher benötigt, sondern quasi nur ein Objekt verlinkt.

    Trotzdem seh ich in Codes oft, dass Pointer verwendet werden.

    Ind der FAQ steht nix und google spuckt auch nix brauchbares aus, also..

    -/beginner\-



  • so so
    http://de.wikipedia.org/wiki/Zeiger_(Informatik)

    pointer können im code einfach "umgebogen" werden, ref. zeigen auf das init objekt und können nicht suddenly woanders hinzeigen



  • wenn du an ner codestelle bist und ned weisst ob du nen zeiger oder ne referenz nehmen sollst stell dir einfach die frage ob die variable jemals NULL sein darf
    wenn ned nimm ne referenz



  • Sovok schrieb:

    wenn du an ner codestelle bist und ned weisst ob du nen zeiger oder ne referenz nehmen sollst stell dir einfach die frage ob die variable jemals NULL sein darf
    wenn ned nimm ne referenz

    davon halte ich gar nix.



  • und warum ned?
    ich find das is der einzige wichtige unterschied beim einsatz von pointern und referenzen als funktionsparameter oder rückgabewerte

    z.b.
    objekt* GetObjFromList( name ); //NULL wenn name nich in der liste
    objekt& GetObjectAt( x, y ); //wenn x und y innerhalb eines gültigen bereichs liegen (assert drauf) kommt immer ein objekt zurück



  • Sovok schrieb:

    und warum ned?

    ich nehme mal deinen praxisnahen code.

    objekt& GetObjectAt( x, y );
    

    hier *weiß* ich, daß x und y nicht verändert wurden. denn sie wurden by value übergeben. hätte die funktion GetObjectAt irgendwelche ambitionen, da was zu ändern, müßte

    objekt& GetObjectAt( &x, &y );
    

    dort stehen.

    ich lege halt wert drauf, die fehlersuchzeiten möglichst zu senken, denn selbst bei defensivster programmierung vbetragen sie noch das zehnfache der eintippzeit. ich weiß jetzt nicht, welchen positiven effekt deine auslegung haben soll.



  • ich versteh deinen post ned so ganz

    objekt& GetObjectAt( x, y );
    

    x und y werden nich verändert und bei value übergeben
    das is auch so gedacht und hat nich direkt was mit dem thema zu tun
    es geht mehr um den rückgabewert

    falls x oder y ungültig is kommt das assert mit ner msgbox und zeigt mir direkt
    die codezeile. der callstack sagt mir woher der fehler kommt
    somit is die fehlersuchzeit extrem kurz

    der positive effekt einer referenz is ganz einfach

    machwas_mit_dem_objekt(objekt&);
    

    bei nr.1

    objekt* pObjekt = GetObjFromList( name );
    
    if ( pObjekt != NULL )
    {
      machwas_mit_dem_objekt( *pObjekt );
    }
    

    bei nr.2

    machwas_mit_dem_objekt ( GetObjectAt( x, y ) );
    


  • Sovok schrieb:

    ich versteh deinen post ned so ganz

    das ist mir klar. ich schreibe auch für die anderen.

    objekt& GetObjectAt( x, y );
    

    x und y werden nich verändert und bei value übergeben

    das steht nirgends! und ich behaupte mal, x und y ständen der veränderung anheim. du mit deinem referenzenwahn müßtest x und y by ref übergeben. und das eben ist humbug. firlefanz. x und y übergibt man per zeiger, wenn man sie der änderung anheimstellt, um zu dokumentieren, daß sie verändert werden können. das ist viel wichtiger, als null-sein oder nicht. denn ein null-fehler taucht einmal auf, der debugger schmeißt einen sicher und zuverlässig auf die code-zeile, wo er kam. man schaut den call-stack an und in nullkommanix ist der fehler weg. wobei um genau zu sein, solche fehler gar nicht vorkommen. nur bei lügenden dokus. und dann sind sie halt auch schnell gefunden und gereppt.

    das is auch so gedacht und hat nich direkt was mit dem thema zu tun
    es geht mehr um den rückgabewert

    haste aber nicht gesagt, daß´deine zauberregel nur für rückgabewerte gilt.

    falls x oder y ungültig is kommt das assert mit ner msgbox und zeigt mir direkt
    die codezeile. der callstack sagt mir woher der fehler kommt
    somit is die fehlersuchzeit extrem kurz

    oh, genau mein argument, neicht deine zauberregel für übergabeparameter zu verwenden, sondern eine nützlichere.

    der positive effekt einer referenz is ganz einfach

    machwas_mit_dem_objekt(objekt&);
    

    bei nr.1

    objekt* pObjekt = GetObjFromList( name );
    if ( pObjekt != NULL )
    {
      machwas_mit_dem_objekt( *pObjekt );
    }
    

    bei nr.2

    machwas_mit_dem_objekt ( GetObjectAt( x, y ) );
    

    das glaube ich nicht ganz, Sovok!

    beachte

    objekt* pObjekt = GetObjFromList( name );
    machwas_mit_dem_objekt( *pObjekt );
    

    und

    objekt objekt = GetObjFromList( name );
    machwas_mit_dem_objekt( objekt );
    

    deine toller referenztrick führt nur dazu, daß der coder noch mehr aufpassen muß als vorher. du baust ihm ne lib, wo er unfug macht, den der compiler zuläßt.

    ob ich den pObject testen muss, hängt allein davon ab, ob ich vorher garantieren konnte, nur gültige namen zu verwenden. und bestimmt nicht davon, ob's ein zeiger oder eine referenz ist. willst du bei jeder änderung der implementierung den typ ändern? wie leicht kommt es vor, daß ich zuerst davon ausgehe, daß nur gültige namen gegeben werden (um den prototyp schnell auf den beinen zu haben), dann auch ungültige namen zulasse, weil ich benutzereingaben hab, dann die benutzerschneittstelle verbessere und nur noch gültige namen hab. dann ach von files einlese und wieder ungültige namen zulasse. dann dem file-reader nen parser verpasse, der zufällich auch ungültige namen erkennt.

    nach deiner lehre würde ich jedesmal wieder zwischen ref und zeiger umschalten. das ist ja noch grauenhafter als ungarische notation.



  • referenzwahn? zauberregel? HALLO?
    jungchen ich hab nur gesagt, dass manchmal das eine und manchmal das andere sinnvoller is. komm mal wieder runter

    ehrlichgesagt kommen solche änderungen der schnittstelle
    bei mir nich oft vor und es werden dort sowieso nur pointer verwendet um c kompatibel zu sein

    schließlich sieht der ablauf in etwa so aus
    planung->implementierung->weitergabe an den enduser->programmierung der extrawünsche->abschluss
    und ab dann nur noch in notfällen änderungen am interface um die abwärtskompatibilität zu wahren

    wenn ich von der wahl zwischen pointern und referenzen spreche geht es
    immer um das handling von internen daten über die ich als programierer die volle kontrolle habe

    deine toller referenztrick führt nur dazu, daß der coder noch mehr aufpassen muß als vorher. du baust ihm ne lib, wo er unfug macht, den der compiler zuläßt.
    

    kannst du das mal bitte näher erläutern

    ob ich den pObject testen muss, hängt allein davon ab, ob ich vorher garantieren konnte, nur gültige namen zu verwenden. und bestimmt nicht davon, ob's ein zeiger oder eine referenz ist.
    

    bei einer referenz sage ich aber als programmierer, dass ich einen gültigen wert garantiere

    irgendwie kann man schließlich immer unfug machen wenn man will
    machwas_mit_dem_objekt( (objekt*) 0x12345 );



  • Sovok schrieb:

    referenzwahn? zauberregel? HALLO?
    jungchen ich hab nur gesagt, dass manchmal das eine und manchmal das andere sinnvoller is.

    da bezog ich mich wohl auf

    wenn du an ner codestelle bist und ned weisst ob du nen zeiger oder ne referenz nehmen sollst stell dir einfach die frage ob die variable jemals NULL sein darf wenn ned nimm ne referenz

    das nenne ich zauberregel und referenzwahn.
    zauberregel, weil sie mich in ihrer halbwissenschaftlichen begrundung an die alchemisten und zauberer des mittelalters erinnert.
    und referenzwahn, weil sie bei konsequenter auslegung zu einem strlen, dem man nucht NULL übergeben darf zu

    size_t strlen(char const& str);
    

    führt.

    ehrlichgesagt kommen solche änderungen der schnittstelle
    bei mir nich oft vor

    bei mir auch nicht, es war ein extrembeispiel, das aber noch durchaus im rahmen des möglichen ist.

    planung->implementierung->weitergabe an den enduser->programmierung der extrawünsche->abschluss

    ich trenne die ersten beiden nur sehr schwach. oder anders ausgedrückt, lerneffekte in der implementierungsphase lasse ich so früh wie möglich und so umfassend wie möglich sofort wieder in die architektur einfließen.

    deine toller referenztrick führt nur dazu, daß der coder noch mehr aufpassen muß als vorher. du baust ihm ne lib, wo er unfug macht, den der compiler zuläßt.
    

    kannst du das mal bitte näher erläutern

    ich gehe davon aus, daß die schnittstelle sich auch noch ändert. wenn ich daten meine, die ich nicht kopieren soll, dann drücke ich das als zeiger aus. du nimmst wanimmer möglich eine referenz. wenn statt der referenz wegen irgendwas doch ein ganzes objekt geliefert werden muss, und die schnittstelle geändert wird, bemerkt dein benutzer das nicht. schlimmstenfalls merkt er sich eine referenz auf ein temporäres objekt und wird sich irgendwann (nach auslieferung am besten) schwer wundern. bei mir kann das gar nicht sein.

    ob ich den pObject testen muss, hängt allein davon ab, ob ich vorher garantieren konnte, nur gültige namen zu verwenden. und bestimmt nicht davon, ob's ein zeiger oder eine referenz ist.
    

    bei einer referenz sage ich aber als programmierer, dass ich einen gültigen wert garantiere

    und das hat vorteile und auch nachteile.

    irgendwie kann man schließlich immer unfug machen wenn man will
    machwas_mit_dem_objekt( (objekt*) 0x12345 );

    komm mal wieder runter

    ok. einigen wir uns drauf, daß du die regel nicht verteidigst und ich greife sie nicht an. und dem gelehrigen schüler beginner_at haben wir gezeigt, daß das thema viel zu vielschichtig ist, um mit einer einfachen regel abgetan zu werden.

    es sei noch erwähnt, daß referenzen performanter sein können. und zwar dann, wenn der compiler ordentliche exceptions erzeigt bei zugrifen auf 0 (statt coredumps, schutzverletzungen). dann muß er nämlich innerhalb der funktion beim ersten zeigerzugriff auf eine bestimmte variable eine exception ermöglichen (bei den folgenden nicht mehr). bei der referenz braucht er das nicht zu machen.



  • size_t strlen(char const* str);
    

    is eine c funktion aus der libc

    es scheint einfach nie ne c++ variante geschrieben worden zu sein

    wenn statt der referenz wegen irgendwas doch ein ganzes objekt geliefert werden muss, und die schnittstelle geändert wird, bemerkt dein benutzer das nicht. schlimmstenfalls merkt er sich eine referenz auf ein temporäres objekt und wird sich irgendwann (nach auslieferung am besten) schwer wundern. bei mir kann das gar nicht sein.
    

    ok in dem punkt stimm ich dir zu... aber bei internen schnittstellen is das ja zweitrangig weil man ja selber die volle kontrolle hat



  • ich machs so:

    bei Funktionsargumenten:

    // Argument wird sicher nicht veraendert:
    bool foo(const Object& arg);
    
    // Argument wird veraendert
    bool foo(Object* arg);
    

    Dann seh ich bereits beim Lesen des Codes, wo wirklich etwas "absichtlich" by Reference uebergeben wird um das Objekt zu veraendern und wo die Uebergabe by Reference nur aus Geschwindigkeitsgruenden (langsamer Copy-Ctor) verwendet wird.

    Ansonsten glaub ich ist Sovok's "Zauberregel" nicht ganz falsch. Ich bin mir nicht sicher, ob sie immer passt, aber ich glaub als Grundregel (die man logisch ggf. auch mal verletzen darf) kann man sie schon beibehalten.



  • muß den alten Thread nochmal rauskramen:

    nachdem ich in letzter Zeit ziemlich häufig dem functor-Wahn verfallen bin, habe ich mich etwas diszipliniert und nun doch ein bisschen häufiger mit den adaptern herumprobiert. Dabei bin ich auf folgendes Problem gestoßen:

    int DbWriteContainer::SynchronizeDiagnosticTranslation( DiagnosticReader& theReader )
    {
    	for_each( begin(), end(), bind2nd( mem_fun( &DiagnosticWriter::SynchronizeDiagnosticTranslationPtr ), &theReader ) );//funktioniert
    	for_each( begin(), end(), bind2nd( mem_fun( &DiagnosticWriter::SynchronizeDiagnosticTranslation ), &theReader ) );//funktioniert nicht -> kann Referenz nicht binden
    
    	return true;
    }
    
    //Auszug aus dem DiagnosticWriter
    
    class DiagnosticWriter : public DbWriteWrapper
    {
    public:
    	virtual void SynchronizeDiagnosticTranslation( DiagnosticReader& theWrapper ) = 0;//Synchronizes the translation rules of the DiagnosticReader with the own Diagnostic representation
    	virtual void SynchronizeDiagnosticTranslationPtr( DiagnosticReader* pWrapper ){ SynchronizeDiagnosticTranslation( *pWrapper ); }//yust a adapter to be usable with for_each
    };
    

    nach längerem Rumprobieren hab ich dann die SynchronizeDiagnosticTranslationPtr eingefügt, da mir bind2nd partout die Referenz-Version nicht binden wollte.

    Glaube ich diesem Artikel: http://dbforums.com/t523901.html :

    It's funny how folks here tell newbies to use t& instead of *t, but when
    you really use the language, you almost have to use pointers.

    wäre das ein Pluspunkt für Pointer (zumindest, wenn man die Funktion mit den bindern benutzen will). Mir ist nur nicht klar, warum man eine Referenz nicht auch binden können soll.


Anmelden zum Antworten