Wann Referenzen, wann Pointer?
-
volkard schrieb:
RHBaum schrieb:
versuch das mal mit referenzen und sauberen C++ Stil
Der Stil wird durch Referenzen nicht sauberer. Ihr überstrapaziert die Referenzen.
Sehe ich anders. Wenn ich Zeiger übergebe ist NULL zulässig, und das ist zumindest bei den überwiegenden Fall in den Programmen, eher die Ausnahme als die Regel. Einer Referenz sieht man an, das ein Wert erwartet wird, einem Zeiger nicht. Einen Zeiger muss man zudem eigentlich immer vor der Verwendung prüfen. Ich glaube daher schon, das Referenzen immer Zeigern vorzuziehen sind, wenn man letztere nicht benötigt.
volkard schrieb:
Das ist die selbe Schiene wie das Verwenden von std::string für *alle* Zeichenketten, weil es "mehr C++" ist. Nix gut.
Ich sehe in der überwiegenden Mehrzahl keine Gründe die für char-Arrays gegenüber (einer wie auch immer gearteten) Stringklasse sprechen.
-
volkard schrieb:
Aber den Haupt-Code verschlimmern sie leider.
Warum? Nur weil du nicht von außen siehst wo eine Variable geändert wird?
-
IntelliSense zeigt das doch an.
-
EOutOfResources schrieb:
IntelliSense zeigt das doch an.
Nicht jeder hat IntelliSense
-
wwwwwwwwwww schrieb:
volkard schrieb:
Aber den Haupt-Code verschlimmern sie leider.
Warum? Nur weil du nicht von außen siehst wo eine Variable geändert wird?
Das siehst du aber auch keinen Zeiger an.
-
asc schrieb:
wwwwwwwwwww schrieb:
volkard schrieb:
Aber den Haupt-Code verschlimmern sie leider.
Warum? Nur weil du nicht von außen siehst wo eine Variable geändert wird?
Das siehst du aber auch keinen Zeiger an.
Volkard benutzt bestimmt nur dort Zeiger, wo die Parameter auch geändert werden. Sehr diszipliniert. Respekt. :p
-
volkard schrieb:
Der Stil wird durch Referenzen nicht sauberer.
Ihr überstrapaziert die Referenzen. Das ist die selbe Schiene wie das Verwenden von std::string für *alle* Zeichenketten, weil es "mehr C++" ist. Nix gut.
Die Referenzen mußten für die Operatorenüberladung erfunden werden. Ok, jetzt haben wir sie. Aber den Haupt-Code verschlimmern sie leider. Deswegen empfiehlt Onkel Volkard: Sparsam einsetzen.Wow! Ich hätte dir niemals derart liberales Gedankengut zugetraut...
Und insbesondere die indirekte Verherrlichung von char-Arrays... also pfui! Und sowas in einem C++-Forum, wo der STL-Monotheismus exzessiv praktiziert und propagiert wird!Im Übrigen halte ich es so wie einige andere auch.
Wann immer es geht übergebe ich per Referenz wenn möglich auch const. Wo es NULL sein darf, auch mal Pointer... Ich bin also flexibel in der Anwendung
-
asc schrieb:
Das siehst du aber auch keinem Zeiger an.
Aber manch einer erwartet es bei einem Pointer vielleicht eher.
Du vielleicht nicht, ich auch nicht, aber andere schon.
-
Meiner Meinung nach ist der Punkt der:
Wenn ich einen Pointer übergebe, dann weiß ich, daß das Objekt, auf das gezeigt wird, geändert werden kann, ohne dass ich mir die Deklaration/Definition der aufgerufenen Funktion ansehen muss.
Wenn ich ein Objekt übergebe, dann sehe ich an der Aufrufstelle nicht, ob die aufgerufene Funktion das als Objekt oder als Referenz nimmt. Bei der Entwicklung ist mir das noch relativ egal, wenn ich aber nach längerer Zeit den Quellcode ansehen muss, dann finde ich es hilfreich, wenn ich mich darauf verlassen kann, dass ein übergebenes Objekt nach Rückkehr noch genau so aussieht wie vor dem Aufruf. Deshalb halte ich es grundsätzlich wie Volkard:
Pointer, wenn die Funktion den Paramter ändert, anderenfalls konstante Referenzen.
-
Ihr tut immer alle rum von wegen Intellisense, Intellisense, Intellisense und seid dann nicht in der Lage, euch den Funktionskopf der auzurufenden Funktion, der ja meist automatisch eingeblendet wird, anzugucken? ohje...
Meist erkennt man ja schon im Funktionkopf an der Referenz, dem Pointer, oder der const Referenz, ob das Objekt möglicherweise in der Funktion geändert wird, oder nicht geändert wird.
-
Man kann auch seine Funktionsnamen so wählen, dass man sieht, ob die Funktion etwas am übergebenen Objekt ändert. Ich persönlich finde das ja doch übersichtlicher...
-
Bis vor einiger Zeit habe ich es genau so gehalten, ich habe diese Argumente vor Jahren gelesen und fand sie logisch.
Mittlerweile nutze ich aber auch konstante und nichtkonstante Referenzen, Zeiger sind bei mir eine Garantie dafür, dass sie auch 0 sein dürfen.
Ist imho auch eine ganz gute Konvention und spart das ständige gegen 0 testen.
Außerdem muss man davon ausgehen, dass eine Funktion, die nichtkonstante Parameter als Referenz entgegen nimmt, diese auch ändert.
-
It0101 schrieb:
Ihr tut immer alle rum von wegen Intellisense, Intellisense, Intellisense und seid dann nicht in der Lage, euch den Funktionskopf der auzurufenden Funktion, der ja meist automatisch eingeblendet wird, anzugucken? ohje...
Meist erkennt man ja schon im Funktionkopf an der Referenz, dem Pointer, oder der const Referenz, ob das Objekt möglicherweise in der Funktion geändert wird, oder nicht geändert wird.
Für Intellisense müßte ich mit der Maus rumfahren. Naja, ich benutze weder Intellisense noch Debugger, aber das ist ein anderes Thema.
Den Funktionskopf muß ich nichtmal angucken bei meinem Stil. Ich sehe es schon am Aufruf. Das ist lecker.Und daß ich mal einem Zeigerparameter erlauben würde, NULL zu sein, das kommt glaube ich nur in der rekursiven Baumtraversierung vor und sonst gar nirgends. Deswegen brauche ich dafür keine Unterscheidung.
-
yahendrik schrieb:
Ist imho auch eine ganz gute Konvention und spart das ständige gegen 0 testen.
Zirkelschluß. Man soll nicht jeden übergebenen Zeiger gegen 0 testen, denn Zeiger bedeuten nicht automatisch, daß der Anwender das Recht hätte, 0 zu übergeben. Was soll auch 0 bedeuten? Daß ich ein Objekt nicht anlegen konnte, daß ich die Ini-Datei nicht lesen konnte? Da ist doch längst eine Exception geflogen. Die Suchfunktionen geben auch nicht mehr 0 zurück, sondern end(). Wie schubse ich mir in C++ eine 0 ins Programm? Und wozu?
Dein ständiges Geteste entspringt dem Gedanken, Zeiger würden das aussagen, und taugt daher nicht mehr viel, um genau den Gedanken zu begründen.
-
Bei mir kommt das schon hinundwieder mal vor, dass Pointer NULL sind.
Denn es ist ja oft auch eine Aussage, dass z.B. bestimmte Daten nicht geliefert wurden, oder fehlerhaft geliefert wurden, so dass der Empfänger dann mit NULL auch eine Aussage geliefert bekommt. Klar kann man das auch anders machen, aber NULL langt meist.
-
Belli schrieb:
Wenn ich einen Pointer übergebe, dann weiß ich, daß das Objekt, auf das gezeigt wird, geändert werden kann, ohne dass ich mir die Deklaration/Definition der aufgerufenen Funktion ansehen muss.
Man kann sowohl den Zeiger als auch das Objekt auf das gezeigt wird als Parameter konstant deklarieren, ein Zeiger alleine ist daher noch kein Garant dafür das man etwas ändert. Eine gewisse Sicherheit gibt daher nur der Blick auf die Funktionsdeklaration.
Belli schrieb:
Wenn ich ein Objekt übergebe, dann sehe ich an der Aufrufstelle nicht, ob die aufgerufene Funktion das als Objekt oder als Referenz nimmt.
Genauso wenig wie du davon ableiten kannst ob es verändert wird oder nicht, und das gilt auch für den Zeiger.
Belli schrieb:
Bei der Entwicklung ist mir das noch relativ egal, wenn ich aber nach längerer Zeit den Quellcode ansehen muss, dann finde ich es hilfreich, wenn ich mich darauf verlassen kann, dass ein übergebenes Objekt nach Rückkehr noch genau so aussieht wie vor dem Aufruf.
Ich auch, nur setze ich dafür auf const, und nicht auf Referenz vs. Zeiger, zumal letzteres ja durchaus beabsichtigt sein kann wenn 0 zulässig ist.
Belli schrieb:
Deshalb halte ich es grundsätzlich wie Volkard:
Pointer, wenn die Funktion den Paramter ändert, anderenfalls konstante Referenzen.Für mich gilt wiederum: Zeiger wo nötig, Referenzen wo (sinnvoll) möglich und const wenn etwas nicht geändert wird (Bei Zeigern jeweils mit Unterscheidung der Adresse oder des Wertes). Dafür dient das Schlüsselwort const ja schließlich auch.
-
It0101 schrieb:
Bei mir kommt das schon hinundwieder mal vor, dass Pointer NULL sind.
Denn es ist ja oft auch eine Aussage, dass z.B. bestimmte Daten nicht geliefert wurden, oder fehlerhaft geliefert wurden, so dass der Empfänger dann mit NULL auch eine Aussage geliefert bekommt. Klar kann man das auch anders machen, aber NULL langt meist.Also muß man C-Stil proggern, um eurer Stil-Argumentation folgen zu können?
Das erkärt natürlich alles.Nein, das erklärt auch nichts.
Nur, weilFoo* f=loadFoo();
fehlschlägt, mache ich doch nicht danach
workFoo(f);
, sondern teste sofort
if(f==0)
und mache zum Beispiel
if(!f) f=vreateDefaultFoo(); if(!f) teminexit();
Außerdem würde ich nicht
workFoo(f);
schreiben, sondern
f->work();
und hoffentlich mache ich nicht
if(!this)
(Die ganze Zeit Angst hab, daß destroyFoo(f) vergessen wird, wenn eine Exception fliegt. Wenn mir doch bloß was einfallen würde, wie ich das elegant vermeide.)
-
Wenn ich mich beim Design meiner Funktionen an die erwähnte Vorgehensweise halte, dann habe ich keine Zeiger auf konstante Objekte als Funktionsparameter.
Und dann sehe ich direkt an der Aufrufstelle, dass mein Objekt verändert werden könnte, wenn ich einen Zeiger übergeben muss.
Wenn ich stattdessen ein Objekt übergebe, weiß ich nicht, ob ich eine Kopie oder eine Referenz übergebe, ohne auf die Funktionsdeklaration zu sehen - es sei denn, ich verfahre wie erläutert.
Ich will nach einem halben Jahr nicht erst überlegen, in welcher Datei die aufgerufene Funktion deklariert ist, die Datei öffnen und mir den Funktionskopf ansehen müssen, um zu wissen, ob ich erwarten kann, dass ich mein Objekt unverändert zurückbekomme.Tachyons Vorschlag, dass mit dem Funktionsnamen kenntlich zu machen, könnte ich evtl. noch folgen, wenn ich kreativ genug für entsprechende Namensfindungen wäre.
-
@Volkard: ich neige dazu, in fast allen funktionen, die übergebenen Variablen zu prüfen. Und wenn besagter Funktion die Übergabewerte nicht in den Kram passen ( z.B. Null-Pointer ), dann steht es ihr frei eine Exception zu werfen oder mittels entsprechender Rückgabewerte vergleichbares kundzutun.
Denn was tust du, wenn du einem anderen Entwickler deine Funktion, die ihre Variablen nicht prüft, zur Verfügung stellst und selbiger sie anwendet ohne ohne zu ahnen was das für Konsequenzen haben könnte.
*kabooom*
-
It0101 schrieb:
Denn was tust du, wenn du einem anderen Entwickler deine Funktion, die ihre Variablen nicht prüft, zur Verfügung stellst und selbiger sie anwendet ohne ohne zu ahnen was das für Konsequenzen haben könnte.
*kabooom*
Jup. Und das ist voll ok so. Ich bin kein Kindermädchen. Also doch schon, aber nicht so extrem.
Mal ein fürchterliches Beispiel:bool parseIniFile(FILE* file,std::map<string,string>* settings)
Wer da NULL übergibt, hat doch einen Sockenschuss. Der soll Landschaftsgärtner werden, da muß er nicht so viel mit Computern arbeiten.
Außerdem wäre der Mitarbeiter doch schon lange von strlen, strcat und strcpy rausgeprüft worden. Ich denke, der Mitarbeiter ist hypothetisch und keine reale Gefahr.