Wann ein Zeiger als Parameter wann eine Referenz?



  • roflmao. 😃



  • kann von hier aus nix suchen. die connection bricht immer nach ner minute ab. ich kann nur versuchen, das nächste ma, wenn ich code finde, der deutlich davn profitiert, ihn euch mitzubringen.



  • @Volkrad:

    im Thread: http://www.c-plusplus.net/forum/viewtopic.php?t=81443 hast du eine Variante einer Funktion geschreiben, die der vorherigen entspricht, allerdings einen ostream entgegennimmt, damit man felxibler ist.
    Wieso nimmst ud ihn als non-const-ref entgegen.

    De Regel lautet doch

    benutze non-const-refs nur, wenn es echt notwendig ist.



  • rofl 😃 😃 😃



  • nicht wirklich flexibler. in der hauptsache kaputter.
    warum verwende ich std::swap?
    aus historischen gründen.



  • Hab zwar keine Ahnung wo man im Netz miesen Code findet aber richtig guten Source findet man hier ~~> http://www.tw.ioccc.org/years.html#2000_anderson 😃



  • Das erklärt immernoch nciht, warum du jetzt den ostream als nicht konstante Referenz entgegennimmst und somit gegen deine eigene Regel verstößt.



  • volkard schrieb:

    mach das mal, wenn die leutchen ständig non-const-refs benutzen. da wirste innerhalb von tagen doch durchdrehen.

    Sorry, Missverständnis.

    Ich weiss, dass du Zeiger gerne nimmst. Ich wollte nur wissen, wann du denn dann non const Referenzen nimmst.



  • Helium schrieb:

    Das erklärt immernoch nciht, warum du jetzt den ostream als nicht konstante Referenz entgegennimmst und somit gegen deine eigene Regel verstößt.

    und du hast nicht über meine antwort nachgedacht.
    warum verwende ich std::swap? aus historischen gründen. das ding hat sich in dieser form fest eingebürgert, bevor man erkannte, wie falsch es eigentlich ist. und das gleiche passierte anno dazumal mit virtual void Foo::printAt(ostream& out);. afair sah ich es 1995 beim borland c++ 3.1 in der lib zum ersten mal. das ändert sich nicht von heut' auf morgen. eventuell ändert sich das nie und dan läßt sich es auch mit ein paar ausnahmen leben. aber man muß es ja nicht drauf anlegen, und in völliug anderen zusammenhängen proggen wie die leutchen damals vor 10 jahren.



  • Shade Of Mine schrieb:

    Ich weiss, dass du Zeiger gerne nimmst. Ich wollte nur wissen, wann du denn dann non const Referenzen nimmst.

    kann mich gerade nur an swap und printAt erinnern. evtl immer bei streams. ob technische argumente dafürsprechen? vielleicht. sie werden auf jeden fall vom argument verdeckt, daß man in seinem code einigermaßen konsistent zum rest der welt baen muß. wenigstens bei swap kommt man nicht drumherum. wegen der neuen implementierung von op= mit dem swap-trick.
    und halt, wo es sein muß. also operatoren.
    refs als member habe ich nie. da hakt's bei mir dann einfach aus, daß ich ne ref als member habe, die meine klasse ganz zufällig genau sizeof(void*) bytes größer werden läßt.



  • Ist es nicht immer lästig bei Zeigern zu prüfen, ob sie 0 sind, bevor man sie dereferenziert?



  • nein, wenn du dir sicher sein kannst, dass die zeiger nicht null sind,musst du nicht prüfen.

    eine frage hab ich aber:
    dürfen funktionen, die einen pointer als parameter erwarten die aufgabe des "auf 0 testen" auf den rest des programms auslagern? oder soll in den fällen, wo der funktion kein nullpointer übergeben werden darf,immer innerhalb der funktion getestet werden?



  • am besten ist es wenn die funktion den null-test selber macht. Übersichtlicher und besser gekapselt, weil unsichtbar. das sieht nicht gut aus, wenn vor jeder Funktion, die pointer erwartet, mehrere if-Abfragen stehen.



  • otze schrieb:

    nein, wenn du dir sicher sein kannst, dass die zeiger nicht null sind,musst du nicht prüfen.

    eine frage hab ich aber:
    dürfen funktionen, die einen pointer als parameter erwarten die aufgabe des "auf 0 testen" auf den rest des programms auslagern? oder soll in den fällen, wo der funktion kein nullpointer übergeben werden darf,immer innerhalb der funktion getestet werden?

    Ich halte es für sehr schwer von außen sicherzustellen, dass ein Pointer nie 0 ist. Selbst wenn dies am Anfang der Fall ist, wird durch Erweiterungen und Wartung immer wahrscheinlicher, dass mal ein 0 Pointer übergeben wird. Ein Parameter, der einen Zeiger erwartet, hat die semantische Aussage: "Da kannst du auch 0 reinstecken."

    Dagegen verhindert bei einer Referenz schon der Compiler, dass eine 0 reingesteckt wird. (Mit den bekannten Ausnahmen) Die semantische Aussage ist jedoch: "Da muß ein gültiges Objekt rein."

    Jemand, der das Programm wartet oder erweitert, wird bei Referenzen sicherstellen, dass gültige Objekte übergeben werden. Bei Zeigern wird er aber annehmen, dass 0 übergeben werden kann.



  • wie entstehen überhaupt nullpointer? wie kommen die in die funktion?
    die alten wege sind doch zumeist verschüttet. new wirft ne exception, statt 0 zurückzugeben. wie kommen sonst de nullen rein?

    otze schrieb:

    eine frage hab ich aber:
    dürfen funktionen, die einen pointer als parameter erwarten die aufgabe des "auf 0 testen" auf den rest des programms auslagern? oder soll in den fällen, wo der funktion kein nullpointer übergeben werden darf,immer innerhalb der funktion getestet werden?

    nee, nicht innerhalb testen. und außerhalb auch nicht. *grins*
    im debug-modus dürfen naürlich tests sein. ach, zum glück sind die eingebaut. der debugger springt ja im falle der schutzverletzung an.
    im release-code würde ich mich nicht damit belasten. da darf es einfach nicht mehr vorkommen, daß ne funktion, die keine 0 essen mag, eine zu essen kriegt.
    es kommt auch in der tat nicht mehr vor. meistens hat man ja wenn man schon mit vielen zeigern hantiert, sowas wie einen vector v<User*>. der steckt wiederum immer als attribut in ner meist simplen wrapperklasse drum, die aus v.push_back(new User()) ein users.add(new User()) macht (und manches wie clear() versteckt), also sprechendere namen. außerdem macht er ohne große kosten des weghauen der Users im destruktor. und da isses selten noch notwendig, mitten drin nullzeiger zu behalten. die kamen ja vor, wenn die user-id zugleich arrayindex war. heute macht man gerne ne hashtable oder ne map, um die id auf den arrayindex abzubilden und erkauft sich damit die möglichkeit, auf nollzeiger zu verzichten. mitten rauslöschen geht ja dann mit swappen von zu löschendem mit letztem und löschen des letzten.
    normalerweise sien die arrays, liste, bäume oder hastables satt und ohne einen nullzeiger drin. in den seltenen fällen, daß man mal die alte version mit nullzeigern benutzt, tut ein einziges if(a[i]) dazwichen auch nicht sonderlich weh.



  • Ponto schrieb:

    Jemand, der das Programm wartet oder erweitert, wird bei Referenzen sicherstellen, dass gültige Objekte übergeben werden. Bei Zeigern wird er aber annehmen, dass 0 übergeben werden kann.

    eben nicht.
    bei

    void eingabeStudent(Student* stud);
    

    würdest du da erwarten, daß man nen nullzeiger übergeben darf? irgendwie kann ich mich gerade an gar keine funktion erinnern, die nen nullzeiger essen mag (außer dem operator delete, aber dafür bin ich nicht verantwortlich zu machen!).



  • otze schrieb:

    eine frage hab ich aber:
    dürfen funktionen, die einen pointer als parameter erwarten die aufgabe des "auf 0 testen" auf den rest des programms auslagern? oder soll in den fällen, wo der funktion kein nullpointer übergeben werden darf,immer innerhalb der funktion getestet werden?

    Erstens) Wieso überhaupt einen Zeiger und keine Referenz? Darum geht doch der ganze Thread hier und ich habe im zweiten Post schon gesagt, dass man eigentlich nie Zeiger zu Übergabe braucht. Habe aber ehrlich gesagt nicht wirlich verstanden, ob Volkard mir da jetzt wiedersprochen oder zugestimmt hat 😕

    Zweitens) Wenn eine Funktion einen Zeiger erwartet der nicht null sein darf, muss da _keine_ Abfrage rein. Du schreibst ja selbst, dass man nur prüfen muss wenn man sich nicht sicher sein kann. Die Funktion kann aber nicht wissen, ob ich mir sicher bin oder nicht. Man könnte höchsten ein Assert einbauen um eventuelle "Flüchtigkeits"-Fehler zu vermeiden.

    // ach mist, nun war er schon wieder schneller als ich



  • DrGreenthumb schrieb:

    Erstens) Wieso überhaupt einen Zeiger und keine Referenz? Darum geht doch der ganze Thread hier und ich habe im zweiten Post schon gesagt, dass man eigentlich nie Zeiger zu Übergabe braucht. Habe aber ehrlich gesagt nicht wirlich verstanden, ob Volkard mir da jetzt wiedersprochen oder zugestimmt hat 😕

    da widerspreche ich energisch (wobei ich aber manchmal das gegenteil von dem schreibe, was ich meine), weil mich nicht die implementierung der funktion interessiert. die mache ich einmal und gut ists.
    mich interessiert die imlementierung des aufrufers.
    ob ich da

    cout<<a<<endl;//ok, a ist korrekt
    f(a,b,c);
    g(a,b);
    h(b,c);
    i(a,b,c);
    cout<<a<<endl;//ups, a ist kaput gegangen, wieso nur???
    

    oder

    cout<<a<<endl;//ok, a ist korrekt
    f(a,b,c);
    g(&a,b);
    h(b,c);
    i(a,b,c);
    cout<<a<<endl;//ups, a ist kaput gegangen, es lag offensichtlich an g
    

    stehen habe.
    die fehlersuchzeit beim aufrufenden code sinkt, wenn man konsequent zeiger für non-const-objekte und const-referenzen oder kopien für const-objekte benutzt.



  • volkard schrieb:

    mich interessiert die imlementierung des aufrufers.
    ...
    die fehlersuchzeit beim aufrufenden code sinkt, wenn man konsequent zeiger für non-const-objekte und const-referenzen oder kopien für const-objekte benutzt.

    Der Meinung war ich auch immer, bis ich mich dann doch von der einfacheren Syntax hab überzeugen lassen. Und in der Praxis fahre ich damit gut. Solche Debug-Situationen sind nach meiner Erfahrung nicht wirklich realistisch. Normalerweise haben die Funktionen dann ja doch sprechendere Namen und man sieht anhand des Kontextes auf Anhieb, wer da irgendwo was verändern möchte und wer nicht.
    Jedenfalls sollte man das.



  • volkard schrieb:

    void eingabeStudent(Student* stud);
    

    würdest du da erwarten, daß man nen nullzeiger übergeben darf? irgendwie kann ich mich gerade an gar keine funktion erinnern, die nen nullzeiger essen mag (außer dem operator delete, aber dafür bin ich nicht verantwortlich zu machen!).

    Das kommt auf den Kontext an. Wenn ich jedoch auf keinen Fall einen 0 Zeiger haben will, nehme ich eine Referenz und fertig. Da bleibt nicht viel Interpretationsspielraum.


Anmelden zum Antworten