Wann Referenzen, wann Pointer?



  • 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, weil

    Foo* 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.



  • volkard schrieb:

    Mal ein fürchterliches Beispiel:

    bool parseIniFile(FILE* file,std::map<string,string>* settings)
    

    Wer da NULL übergibt, hat doch einen Sockenschuss.

    Schönes Beispiel. Warum sollte man hier die Map nicht als Referenz nehmen? Bei dem Funktionsnamen denkt doch niemand, die Map sei ein Input-Parameter. Und aus dem gleichen Grund, aus dem man weiß, dass die Map mit Werten befüllt wird, weiß man auch, dass man nicht NULL übergeben darf. Ich jedenfalls finde den Aufruf schöner, wenn ich nicht noch ein hässliches & vor die Variable setzen muss.



  • ipsec schrieb:

    Bei dem Funktionsnamen denkt doch niemand, die Map sei ein Input-Parameter. Und aus dem gleichen Grund, aus dem man weiß, dass die Map mit Werten befüllt wird, weiß man auch, dass man nicht NULL übergeben darf.

    Ok. Beide Stilrichtungen sind also nicht tragend, weil aus dem hübschen Funktionsnamen genug hervorgeht. So muß es auch sein. Schlechte Funktionsnamen akzeptiere ich nicht als Argument.

    ipsec schrieb:

    Ich jedenfalls finde den Aufruf schöner, wenn ich nicht noch ein hässliches & vor die Variable setzen muss.

    Ok, wenn es häßlich ist...

    Mir gefällt es, weil ich beim Anschauen des Codes am & schon sehe, daß dort reingeschrieben wird. Sozusagen schon aus Entfernung, beim leichten drüberfliegen, noch bevor ich den Funktionsnamen ganz lese. Vielleicht habe ich gar keine Lust, immer wieder den Sinn meines Codes zu durchdenken und mag lieber möglichst viel automatisch erfassen ohne auf den Sinn einzugehen.

    Aber sowas wie

    bool parseIniFile(FILE* file,std::map<string,string>* settings)
    

    wird man bei mir eh nicht finden.

    Eher

    Settings::Settings(char const* iniFileName);
    

    und natürlich prüfe ich nicht, ob so ein Hallodri mir als iniFileName einen Nullzeiger übergibt. Das wäre mir einfach zu javaesk.



  • volkard schrieb:

    Settings::Settings(char const* iniFileName);
    

    Also sowas würde ich auch nicht prüfen... Man kann ja nun wirklich nicht jedem Arsch nachtragen... 😃

    Besser wäre da dann wohl:

    Settings::Settings( const std::string &iniFileName );
    

    😃



  • It0101 schrieb:

    Besser wäre da dann wohl:

    Settings::Settings( const std::string &iniFileName );
    

    😃

    Mit dem Aufruf

    Settings s("grangi.ini");//Hab ja doch nur ein Literal
    

    und dem Code

    {
       ifstream in(iniFileName.c_str());//Brauche ja doch nur einen char*
       ...
    


  • volkard schrieb:

    It0101 schrieb:

    Besser wäre da dann wohl:

    Settings::Settings( const std::string &iniFileName );
    

    😃

    Mit dem Aufruf

    Settings s("grangi.ini");//Hab ja doch nur ein Literal
    

    und dem Code

    {
       ifstream in(iniFileName.c_str());//Brauche ja doch nur einen char*
       ...
    

    Genau da ziehe ich aber die const Ref. auf std::string vor.
    Ausserdem halte ich es für einen Fehler in der Standard Lib. dass ifstream ein const char* als File Name nimmt und nicht ein std::string.



  • theta schrieb:

    Ausserdem halte ich es für einen Fehler in der Standard Lib. dass ifstream ein const char* als File Name nimmt und nicht ein std::string.

    Wir müssen ja nicht alles mit Gewalt langsam machen. Ich denke, das tut der Sprache auch ein bißchen weh.
    Aber ich würde es begrüßen, wenn es beide Überladungen gäbe.



  • Mit C++0x wird es beide Überladungen geben, soweit ich weiß.



  • 314159265358979 schrieb:

    Mit C++0x wird es beide Überladungen geben, soweit ich weiß.

    Wichter fände ich es, wenn die fstreams mit einem wchar_t als char-Typ für den Dateinamen klar kommen würde.



  • Tachyon schrieb:

    Wichter fände ich es, wenn die fstreams mit einem wchar_t als char-Typ für den Dateinamen klar kommen würde.

    wchar_t für den namen, aber char für den Inhalt? Dann müssten auch diverse andere Kombinationen angeboten werden.



  • pumuckl schrieb:

    Tachyon schrieb:

    Wichter fände ich es, wenn die fstreams mit einem wchar_t als char-Typ für den Dateinamen klar kommen würde.

    wchar_t für den namen, aber char für den Inhalt?

    Macht durchaus Sinn, da viele OS mit Unicode als Dateinamen klar kommen, für den Inhalt aber durchaus noch ASCII ausreichen kann.



  • volkard: Kann man von dir mal ein größeres Programm (>10000 Zeilen) irgendwo sehen?



  • Ät schrieb:

    volkard: Kann man von dir mal ein größeres Programm (>10000 Zeilen) irgendwo sehen?

    Nein.


Anmelden zum Antworten