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 referenzdavon 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ückgabewertez.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ückgabewertfalls 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 kurzder 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ückgabewerthaste 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 kurzoh, 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 runterehrlichgesagt kommen solche änderungen der schnittstelle
bei mir nich oft vor und es werden dort sowieso nur pointer verwendet um c kompatibel zu seinschließ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 wahrenwenn 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 habedeine 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 zusize_t strlen(char const& str);
führt.
ehrlichgesagt kommen solche änderungen der schnittstelle
bei mir nich oft vorbei 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.