Zeiger oder Referenz
-
volkard schrieb:
swap. schrieb:
Mit dieser Meinung bist du hier ziemlich alleine!
irgend jemand muß ja vorangehen. wir haben lange zeit zu viele referenzen benutzt aus fadenscheiniten gründen, eigentlich nur, weil es geht. du wirst oft hören "nimm immer referenzen, wenn es überhaupt möglich ist und nur im aüßerseten notfall zeiger". aber selten mit guter begründung und nie mit einer, die einer längeren diskussion standhält. weil es nämlich gar nicht so ist, daß man bei zeigern jeden übergebenen wert auf 0 prüfen sollte.
Du glaubst du gehst voran ? Aber nur weil du dich nicht umdrehst und siehst
das alle anderen in die entgegengesetzte Richtung marschieren.

-
m.E. gehoeren Zeiger nur dort hin, wo man sie absolut nicht vermeiden kann.
Referenzen sind aus vielerlei Hinsicht besser: Sie bringen das Fehlerrisko nahe Null, machen den Code lesbarer, und sind fuer den Compiler leichter zu optimieren (da der Geltungsbereich genau definiert ist).
Falls moeglich, sollte man nur Zeiger verwenden, die die Adresse einer Referenz nehmen (z.B. bei Konstruktorparametern).
Am besten ist, man vermeidet auch new- und delete-Operator-Aufrufe. Man kann in C++ ja Objekte auf dem Stack deklarieren, die dann beim Verlassen des Geltungsbereichs automatisch vernichtet werden. Das nicht nur praktisch, sondern auch lesbarer, und bei der Exception-Behandlung muss man sich dann auch um nichts kuemmern.
Manche Leute verwenden gruendsatzlich nur dieses Modell, und verwenden Zeiger nur innerhalb von AutoPointer-Objekten.
Referenzen helfen, C++ Code robust zu machen.
Setzt man Referenzen geschickt ein, kann man in C++ genauso idiotensicher wie z.B. in Java programmieren.
-
Hoffentlich artet das nicht in Streit aus.

volkard hat sowieso Unrecht.
-
Meine bescheidene Laienmeinung tut hier sicher nichts zur Sache, weswegen ich sie nicht kundtun werde, jedoch möchte ich darauf hinweisen, dass Volkard nicht ganz so "alleine" steht wie, behauptet wurde. Stroustrup sagt in "The C++ Language" das selbe unter Anführung gleicher Gründe (S. 107 deutsch, Ausgabe 4).
Zum Überprüfen der Zeiger auf 0: Weiter oben angeführte C++-FAQ impliziert ähnliches in anderem Kontext: http://www.parashift.com/c++-faq-lite/exceptions.html#faq-17.12
(Kurz: dass eine Überprüfung auf 0 von Zeiger-Argumenten nicht immer notwendig ist.)
-
Konrad Rudolph schrieb:
(Kurz: dass eine Überprüfung auf 0 von Zeiger-Argumenten nicht immer notwendig ist.)
Eine Referenz ist kein Zeiger, daher hinkt der Vergleich (falls beabsichtigt).
Die Ueberpruefung von Zeigern auf 0 bringt relativ wenig, da der Fall selten vorkommt, dass ein falscher Zeiger auf die Adresse 0 zeigt.
Ausnahme sind z.B. ungepruefte dynamic_cast<> Aufrufe, sowie andere Aufrufe, die einen 0-Zeiger im Fehlerfall zurueckliefern, der dann ungeprueft als Zeiger verwendet wird. D.h. die Pruefung sollte beim Aufrufer erfolgen und nicht beim Aufgerufenen.
Einziges gutes Argument fuer Zeiger, das mir grade einfaellt, ist, dass die Anzahl von Konstruktoraufrufen durch die Verwendung von Zeigern reduziert werden kann. Dies hat einen definitiven Performance-Impact.
Aber man kann sich dann gleich fragen lassen, warum man C++ und nicht C benutzt. Der Programmieroverhead in C++ wird durch die Verwendung von Zeigern stark erhoeht, und das Fehlerrisiko steigt.
-
Power Off schrieb:
Konrad Rudolph schrieb:
(Kurz: dass eine Überprüfung auf 0 von Zeiger-Argumenten nicht immer notwendig ist.)
Eine Referenz ist kein Zeiger, daher hinkt der Vergleich.
Ich bezog mich auf Volkards Aussage "[...] weil es nämlich gar nicht so ist, daß man bei zeigern jeden übergebenen wert auf 0 prüfen sollte."
Der Programmieroverhead in C++ wird durch die Verwendung von Zeigern stark erhoeht, und das Fehlerrisiko steigt.
Nun, es ging hier doch nur um Parameterübergabe per Zeiger/Referenz und hier entsteht wohl kaum ein Programmieroverhead durch Zeigerverwendung (zumindest, wenn man sich um Nullwerte keine Sorgen macht).
-
Konrad Rudolph schrieb:
Nun, es ging hier doch nur um Parameterübergabe per Zeiger/Referenz und hier entsteht wohl kaum ein Programmieroverhead durch Zeigerverwendung (zumindest, wenn man sich um Nullwerte keine Sorgen macht).
Ja, das stimmt.
Ich mein ja nur. Wenn wir's schon von Referenzen vs. Zeiger haben.

-
Power Off schrieb:
Einziges gutes Argument fuer Zeiger, das mir grade einfaellt, ist, dass die Anzahl von Konstruktoraufrufen durch die Verwendung von Zeigern reduziert werden kann. Dies hat einen definitiven Performance-Impact.
versteh ich nich
im zusammenhang mit referenzen die als argument einer funktion übergeben werden?
wo finden da konstruktorenaufrufe statt?
-
Sovok schrieb:
Power Off schrieb:
Einziges gutes Argument fuer Zeiger, das mir grade einfaellt, ist, dass die Anzahl von Konstruktoraufrufen durch die Verwendung von Zeigern reduziert werden kann. Dies hat einen definitiven Performance-Impact.
versteh ich nich
im zusammenhang mit referenzen die als argument einer funktion übergeben werden?
wo finden da konstruktorenaufrufe statt?Z.B. bei dieser Sequenz:
#include <string> using std::string; void func( const string& str ) { // ... } void func2( void ) { func( "alpha" ); // versteckter Konstruktor-Aufruf: es wird ein temporaeres string-Objekt angelegt // und danach wieder vernichtet. string c = "alpha" + string("beta"); // 2 Konstruktor-Aufrufe, 1 Destruktor-Aufruf, // 1 operator+() Aufruf }
-
Power Off schrieb:
string c = "alpha" + string("beta"); // 3 Konstruktor-Aufrufe, 2 Destruktor-Aufrufe, // 1 operator+() Aufruf }ich zähle aber nur 2 ctor-aufrufe, 1 dtor-aufruf und 1 op+()-aufruf.
/** * @brief Concatenate C string and string. * @param lhs First string. * @param rhs Last string. * @return New string with value of @a lhs followed by @a rhs. */ template<typename _CharT, typename _Traits, typename _Alloc> basic_string<_CharT,_Traits,_Alloc> operator+(const _CharT* __lhs, const basic_string<_CharT,_Traits,_Alloc>& __rhs);
-
volkard schrieb:
ich zähle aber nur 2 ctor-aufrufe, 1 dtor-aufruf und 1 op+()-aufruf.
Stimmt, hast recht. Werd's gleich korrigieren!

-
vorteil von zeigern?
void func( const string* str ) { // ... } void func2( void ) { func( &string ( "alpha" ) ); //wohl eher string c = string ( "alpha" ) + string("beta"); //weil "alpha" sonst nur n zeiger is zu dem du addierst //beim zweiten kann ich den vorteil von zeigern auch nich nachvollziehn //geht schliesslich garned mit zeigern }[/quote]
-
Gast4 schrieb:
volkard hat sowieso Unrecht.
Falsch geraten, Volkard hat immer Recht (naja, fast). Er wird schliesslich nicht umsonst "The Godfather" genannt.

Trotzdem hab ich seine Ansichten bzgl. Referenzen vs. Zeiger in diesem Punkt nie nachvollziehen können. Mir ist es ehrlich gesagt zu unintuitiv, anhand semantischer Feinheiten zu erlesen, was ein Programm macht. Mir ist zB vollkommen egal, ob da
add_something(foo)oder
add_something(&foo)steht. Das einzige was mich interessiert, ist, dass something zu foo addiert wird.
-
Mein Senf muss auch noch dazu.
Ich mache es oft so, dass ich durch die Wahl anzeige was in der Methode passiert.
Nimmt die Methode einen Pointer, dann kann man sich sicher sein, dass die Methode dem Paramerter verändert.
Nimmt die Methode eine (const) Referenz, dann ist man sich sicher, dass die Methode den Parameter nicht verändern kann.Wenn ich programmiere, dann weiß ich ja was die Methoden die ich aufrufe machen.
Wenn ich mir später meinen Code wieder durchsehe und Methodenaufrufe mit '&' sehe, dann weiß ich sofort.. oha.. der will einen Pointer -- gut da passen wir mal auf.
-
Also ich kann volkards Meinung in dem Punkt jetzt auch nicht ganz nachvollziehen. Vielleicht ist das aber auch Teil einer Studie und er will nur schauen wieviele Leute in den nächsten Wochen einfach seine Meinung weiterplappern. Vielleicht kommt er aber auch nachher mit dem Bombenargument und begründet seine Meinung zu Pointern.
Ob die Funktion etwas mit dem übergebenen Objekt macht erkenne ich daran ob die übergebene Referenz const ist oder nicht und Pointer benutze ich nur wenn es mit Referenzen nicht geht bzw. umständlicher wäre. Pointer auf 0 prüfen macht meiner Meinung nach nur dann Sinn wenn das Objekt auch 0 sein kann, also zusätzlich zur Zeigerfunktion einen Status darstellt (diverse Libs machen da regen Gebrauch von).
-
(naja, fast)
genau das meinte ich

-
hehejo schrieb:
Nimmt die Methode einen Pointer, dann kann man sich sicher sein, dass die Methode dem Paramerter verändert.
Nimmt die Methode eine (const) Referenz, dann ist man sich sicher, dass die Methode den Parameter nicht verändern kann.Warum macht man das nicht gleich nur mit Referenzen?
void func( const alpha& a ); // a kann nicht geaendert werden void func( alpha& a ); // a kann geaendert werden
-
Sovok schrieb:
string c = string ( "alpha" ) + string("beta"); //weil "alpha" sonst nur n zeiger is zu dem du addierstDas macht nix, weil es einen operator+( const char*, const string& ) gibt, den Volkard ja aufgelistet hat.
Also ist:string c = "alpha" + string("beta");equivalent zu:
string c( operator+( "alpha", string( "beta" ) ) );
-
Sovok schrieb:
//wohl eher string c = string ( "alpha" ) + string("beta"); //weil "alpha" sonst nur n zeiger is zu dem du addierst }Nein, siehe Volkards letzten Kommentar und seinen Auszug aus den Standard-Headerdateien.
-
groovemaster schrieb:
Trotzdem hab ich seine Ansichten bzgl. Referenzen vs. Zeiger in diesem Punkt nie nachvollziehen können. Mir ist es ehrlich gesagt zu unintuitiv, anhand semantischer Feinheiten zu erlesen, was ein Programm macht. Mir ist zB vollkommen egal, ob da
add_something(foo)oder
add_something(&foo)steht. Das einzige was mich interessiert, ist, dass something zu foo addiert wird.
sematische feinheiten? jup, die würden mich ankotzen. ich will klaren uen einfachen code.
deswegen will ich keine semantischen feinheiten ausdeuteln müssen, sondern *sofort* sehen, was los ist. insbesondere will ich *nicht* überlegen müssen, was die funktion denn bewerkstelligt. ich kann nicht immer aus dem namen genau folgern, was die funktion macht. vor allem, wenn fremde leute die funktionsnamen erfunden haben.
und das geht so:do_something(foo);//call by value, foo belib unverändertoder
do_something(&foo);//foo wird verändert, weil zeigerund sonst nix.
also beim lesen sehe ich immer ganz genau, ob ich das foo nur zeige oder ob ich's zum verändern hergebe. ach, ist das eine freude, wenn man mal ein kaputtes foo hat, und sich überlegen muß, welche funktiopn foo kaputtet hat. kann ja nur eine mit &foo ewesen sein.
außerdem bin ich auch beim programmieren ein wenig feige. sollte das nicht jeder sein? wenn ich meinen funktionen immer nur foo zu fresen gebe, hab ich echt ein besseres gefühl. die paar mal, wo es dann doch &foo sein muß, mach ich das halt, aber immer bewußt. und da weiß ich, daß keiner an meinen daten rumkritzelt, ohne daß ich das bewußt zugelassen habe.
der stil ist also sowas wie const, nur eben als forderung von der callerseite her und nicht als versprechen von der calleeseite her und ergänzt die strenge typprüfung von c++ dahingehend, daß man schon wieder einen haufen aus-versehen-fehler zu compilerfehlern gemacht hat.