Rückgabe von Objekten



  • hm. stimmt okay. irgendwie logisch.
    du kannst gut erklären, danke! 🙂

    ich hab mal gelesen von einer objekterzeugung wo man direkt aufn default ctor drauf zugreift und von einer wo man das nicht tut. irgendwie so gabs da mal was. bin vergesslich lol 🙂


  • Administrator

    Gäbe ja eigentlich noch eine weitere Möglichkeit, erst recht bei Objekten, welche nicht kopierbar sind:

    void function(Connection& con, int param)
    {
      // Wähle dank param was aus, oder was du auch mit param machen willst.
      con.server("google.com");
    }
    
    // ... irgendwo, wo du die Funktion aufrufst ...
    Connection con;      // erstelle das Objekt
    function(con, 645);  // übergib das Objekt zur Bearbeitung.
    

    Grüssli



  • Dravere schrieb:

    Gäbe ja eigentlich noch eine weitere Möglichkeit, erst recht bei Objekten, welche nicht kopierbar sind:

    Connection con;      // erstelle das Objekt
    function(con, 645);  // übergib das Objekt zur Bearbeitung.
    

    die viel sicherer, weil da kein speicherloch entstehen kann, weil man das zugehörige delete nicht vergessen kann.

    aber noch lieber mag ich dann

    Connection con;      // erstelle das Objekt
    function(&con, 645);  // übergib das Objekt zur Bearbeitung.
    

    damit ich sofort erkenne, daß con verändert wird. mir hilft das bei der fehlersuche, besonders, wenn der code schon ne ecke älter ist.


  • Administrator

    volkard schrieb:

    aber noch lieber mag ich dann

    Connection con;      // erstelle das Objekt
    function(&con, 645);  // übergib das Objekt zur Bearbeitung.
    

    damit ich sofort erkenne, daß con verändert wird. mir hilft das bei der fehlersuche, besonders, wenn der code schon ne ecke älter ist.

    Kann man das sofort erkennen? Was ist, wenn das folgende als Funktionsprototyp steht:

    void function(Connection const* con, int param);
    

    Ich finde so einen Code eher fehleranfällig und unhandlich, erst recht um die Funktion zu implementieren, da man eine Fehlerbehandlung einführen muss, falls ein Null-Zeiger übergeben wird. Und was für einen Fehler macht man dann? Assertion, Exception, Return Wert, ignorieren?

    Wenn man ein gültiges Objekt übergeben muss, dann sollte man wohl bei einer Referenz bleiben. So muss der Aufrufer dafür sorgen, dass immer ein gültiges Objekt kommt, wodurch dieser womöglich optimieren kann, da er weiss, dass nie ein ungültiges Objekt übergeben wird. Dadurch fällt die ganze Fehlerbehandlung weg.

    Grüssli

    PS: Sorry, wenn das ein wenig ins Off-Topic geht. Aber ich wäre noch gespannt auf eine Antwort darauf. 🙂



  • volkard schrieb:

    aber noch lieber mag ich dann

    Connection con;      // erstelle das Objekt
    function(&con, 645);  // übergib das Objekt zur Bearbeitung.
    

    damit ich sofort erkenne, daß con verändert wird. mir hilft das bei der fehlersuche, besonders, wenn der code schon ne ecke älter ist.

    Nachteil hierbei ist aber das eine NULL-Prüfung erfolgen muss, die wieder zu einem Fehler führen kann.

    Ich für meinen teil ziehe hier entweder:
    a) Die Referenzübergabe (Da keine Null-Werte zulässig)
    oder
    b) Eine Rückgabe eines Smartpointers (Freigabe geregelt)
    vor.

    cu André



  • Dravere schrieb:

    da man eine Fehlerbehandlung einführen muss, falls ein Null-Zeiger übergeben wird.

    nö, gar nicht. allerhöchstens ein kleines assert(con). ist doch logisch, daß das subjekt nicht 0 sein darf.


  • Administrator

    volkard schrieb:

    nö, gar nicht. allerhöchstens ein kleines assert(con). ist doch logisch, daß das subjekt nicht 0 sein darf.

    Wieso soll das logisch sein? Wenn ein Zeiger erwartet wird und wir nicht in C sind, dann ist es für mich logisch, dass man auch einen Nullzeiger übergeben kann.

    Und über dass assert(con) wird sich der Benutzer freuen, wenn zur Laufzeit ein Fehler passiert, weil er dachte, dass man auch einen Nullzeiger übergeben darf.
    Noch lustiger wird es, wenn im Debugmodus irgendwie der Fehler nie erreicht wurde, da immer ein gültiges Objekt übergeben wurde. Release erstellt, an den Kunden ausgeliefert. Der Arbeitet und plötzlich -> Fatal Error oder sonst ein Fehler, da auf einen Nullzeiger zugegriffen wurde. Alle Daten verloren ...

    Grüssli



  • volkard schrieb:

    nö, gar nicht. allerhöchstens ein kleines assert(con). ist doch logisch, daß das subjekt nicht 0 sein darf.

    Nein, Ein Zeiger impliziert auch das man 0 verwenden darf.
    Ich schaue doch nicht in die Implementierung um zu sehen ob 0 zulässig ist oder nicht. Bei der Referenzübergabe geht es garnicht anders, und hier muss man nur die Deklaration kennen um sauber zu programmieren!

    cu André



  • asc schrieb:

    Nein, Ein Zeiger impliziert auch das man 0 verwenden darf.

    nö. die spracher erlaubt es. aber das ist auch schon alles.
    bevor du weiter sowas sagst, würde ich gerne wissen, was gibt strlen(0) eigentlich zurück?



  • volkard schrieb:

    nö. die spracher erlaubt es. aber das ist auch schon alles.
    bevor du weiter sowas sagst, würde ich gerne wissen, was gibt strlen(0) eigentlich zurück?

    Keine Ahnung, da ich C-Funktionen nur dann einsetze wenn C++ wirklich ein Flaschenhals in der Anwendung ist, oder begrenzt an DLL-Schnittstellen. Und ersteres habe ich bislang nur äußerst selten im Praxiseinsatz erlebt.

    P.S: Und Diskussionen über C-Schnittstellen wären glaube ich eher im C-Forum passend, oder?


  • Administrator

    volkard schrieb:

    bevor du weiter sowas sagst, würde ich gerne wissen, was gibt strlen(0) eigentlich zurück?

    Wenn ich da auch noch was hinzufügen darf neben den Argumenten von asc.
    Seit wann hat die Sprache C:
    a) Referenzen? Daher ist es ziemlich witzig, dass du eine C Funktion nennst.
    b) Klassen? Man kann einen String in C gar nicht anders als über einen Zeiger implementieren.

    Wie es asc gesagt hat, wir sind hier im C++ Forum.

    Grüssli



  • sie schmiert ab. und das ist nicht schlimm. so grobe programmierfehler muss keiner fangen.



  • Dravere schrieb:

    Wieso soll das logisch sein? Wenn ein Zeiger erwartet wird und wir nicht in C sind, dann ist es für mich logisch, dass man auch einen Nullzeiger übergeben kann.

    Bevor ich so eine "Logik" anwende, würde ich mich über die Preconditions der Funktion schlaumachen.

    Und über dass assert(con) wird sich der Benutzer freuen, wenn zur Laufzeit ein Fehler passiert, weil er dachte, dass man auch einen Nullzeiger übergeben darf.

    Seit wann übergeben Benutzer Nullzeiger? Das wird schon noch ein anderer Programmierer gewesen sein, und zwar einer, der eher obige "Logik" bevorzugt.

    C-Funktionen

    Dann nimm halt eine C++-Funktion, die einen char-Pointer erwartet. Den Konstruktor von ifstream z.B.



  • Bashar schrieb:

    Dravere schrieb:

    Wieso soll das logisch sein? Wenn ein Zeiger erwartet wird und wir nicht in C sind, dann ist es für mich logisch, dass man auch einen Nullzeiger übergeben kann.

    Bevor ich so eine "Logik" anwende, würde ich mich über die Preconditions der Funktion schlaumachen.

    Die meisten Referenzen die ich kenne, erwähnen diese nicht. Davon ganz abgesehen:

    Wenn man die Preconditions bereits an der Deklaration erkennt, halte ich dies für eine bessere Wahl, als das man erst einmal die Dokumentation suchen muss.

    Bashar schrieb:

    C-Funktionen

    Dann nimm halt eine C++-Funktion, die einen char-Pointer erwartet. Den Konstruktor von ifstream z.B.

    Es gibt einen guten Grund warum die C++Funktionen im kommenden Standard in diesen Punkt umgestellt werden.



  • asc schrieb:

    Wenn man die Preconditions bereits an der Deklaration erkennt, halte ich dies für eine bessere Wahl, als das man erst einmal die Dokumentation suchen muss.

    für mich ist const/nichtconst ein viel wichtigerer punkt, den ich ohne doku wissen will, als null/nichtnull.
    die versehentliche annahme, ein objekt werde nicht verändert, kann für viel längere suchzeiten sorgen, als die versehentliche verwendung der 0. vorausgesetzt, daß man einen debugger hat. und die const/nichtconst-fehlannahmen kommen häufiger vor, hab ich das gefühl. daher bevorzuge ich meine "Logik" und die verträgt sich einfach nicht mit eurer. mir scheint, eure enstand aus einem unverständnis und im informationsvakuum hat man sich dummerweise am verbot von nullreferenzen festgehalten und verasucht, damit eine fehlervermeidende regel zu basteln. meyers gelesen und auch mal meyers sein wollen. und sich keine gedanken gemacht, was wirklich fehler vermeidet.



  • volkard schrieb:

    Dravere schrieb:

    da man eine Fehlerbehandlung einführen muss, falls ein Null-Zeiger übergeben wird.

    nö, gar nicht. allerhöchstens ein kleines assert(con). ist doch logisch, daß das subjekt nicht 0 sein darf.

    Hmmmm ... mal eine etwas andere Frage: Anhand wessen sollte man sich überhaupt zwischen Zeigern oder Referenzen unterscheiden?

    Mein persönliches Kriterium war bislang immer: "Ist es nullable oder verschiebbar, nimm Zeiger; sonst Referenz."
    (Was nicht bedeutet, dass das das beste/einzige/sinnvollste/... Kriterium sei - eben nur mein(bisherige)s).

    Ob es sich um einen Input- oder einen update-Parameter handelt, würde ich persönlich nur anhand der Schnittstelle (const oder non-const; gilt für Zeiger genauso wie für Referenzen) entscheiden ...

    Gruß,

    Simon2.



  • asc schrieb:

    Die meisten Referenzen die ich kenne, erwähnen diese nicht.

    Schön, aber was willst du damit ausdrücken? Dass du nichts von der Dokumentation von Kontrakten hältst oder wie?

    Wenn man die Preconditions bereits an der Deklaration erkennt, halte ich dies für eine bessere Wahl, als das man erst einmal die Dokumentation suchen muss.

    Man erkennt leider nicht an der Deklaration, ob Nullzeiger erlaubt sind oder nicht. Ansonsten siehe volkard.

    Bashar schrieb:

    Dann nimm halt eine C++-Funktion, die einen char-Pointer erwartet. Den Konstruktor von ifstream z.B.

    Es gibt einen guten Grund warum die C++Funktionen im kommenden Standard in diesen Punkt umgestellt werden.

    Und du meinst, der Grund wäre, dass die Leute sich nicht darüber im klaren sind, dass man da keinen Nullzeiger übergeben darf? Du weichst der Frage aus.



  • Simon2 schrieb:

    Mein persönliches Kriterium war bislang immer: "Ist es nullable oder verschiebbar, nimm Zeiger; sonst Referenz."

    Meins ist: Referenzen nur wenns const-Referenzen sein können, also nur zum unsichtbaren beschleunigen.

    Allerdings kommt die Frage ja eh nur sehr selten auf und wird mit der Zeit immer seltener. Die Connection zum Beispiel wird vermutlich einen Konstruktor haben, der connected.



  • Simon2 schrieb:

    Mein persönliches Kriterium war bislang immer: "Ist es nullable oder verschiebbar, nimm Zeiger; sonst Referenz."
    (Was nicht bedeutet, dass das das beste/einzige/sinnvollste/... Kriterium sei - eben nur mein(bisherige)s).

    Sehe ich ähnlich. Und damit dokumentiert die Angabe Referenz/Zeiger auch, ob NULL zulässig ist oder nicht. Wenn es nicht änderbar sein soll hantiere ich zusätzlich mit const.



  • Ich versuche auch wenn möglich Referenzen zu verwenden. Ich finde nicht, dass es sich wegen dem Schneller Erkennen lohnt, einen Zeiger zu erlauben. Nicht nur, weil dann Null übergeben werden kann; bei einer Referenz ist auch garantiert, dass sie nicht geändert wird und bei der Initialisierung auf ein gültiges Objekt zeigen muss. Ein hübscher Nebeneffekt ist gerade, dass man sich die Dereferenzierungssyntax sparen kann. Wieso sollte ich einen Zeiger verwenden, wenn ich das Ganze mit Referenzen tun kann und damit mehr Einschränkungen möglich sind?

    Viele Funktionen, die man verwendet, kennt man entweder bereits, oder die IDE unterstützt einen beim Schreiben der Argumentliste, indem sie die Parametertypen mitteilt. Spätestens wenn ich da eine Referenz sehe, ist mir klar, dass das Objekt verändert werden kann. Dazu braucht es keinen Adressoperator beim Aufruf.


Anmelden zum Antworten