Stilfrage: T& a oder T &a



  • not smart schrieb:

    für mich gehören referenzen usw einfach zum typen (mehrere definitionen in einer zeile sind sowieso das unleserlichste was ich mir vorstellen kann, mach ich nie).

    Alles außer dem Bezeichner (und dem Initialisierer) gehört in einer Deklaration zum Typ. Insbesondere gehören dazu auch Elemente, die rechts vom Bezeichner stehen, z.B. Array-Klammern und Parameterlisten.


  • Mod

    funkyunicoder schrieb:

    camper schrieb:

    Mehrfachdefinitionen in einer Zeile sind evil\sqrt{\forall evil}

    Mehrfachdeklarationen in einer Zeile (Funktionsparameter) sind quasi unvermeidbar. Wenn es logisch passt finde ich das sogar empfehlenswert, z.B. iter begin, end;

    Sobald Initializer im Spiel sind, mache ich sofort mehrere Zeilen.
    Auch bei Funktionen mache ich des öfterensehr oft mehrere Parameter in getrennten Zeilen. Wer noch?

    Eine Variablendefinition benötigt einen 1. Typ, 2. einen Bezeichner, und 3. einen Initialisierer.

    Pauschal falsch. Ein Deklarator kann einen Initializer angeben.

    Ich habe einen sehr einheitlichen Stil, der von euch aber wahrscheinlich als inkonsistent aufgefasst werden wird. Ich schreibe

    T* a;
    // aber
    T *a, *b;
    

    Das hat nichts mit der Interpretation zu tun - ich sehe direkt, was ein Zeiger ist und was nicht. Ich mag es allerdings, Dinge schön geordnet und in Blöcke zu schreiben. Bei ersterem Fall jedoch tendiere ich einfach (aus Gewohnheit?) dazu, das Asterisk an den Typ zu schreiben.

    Tatsächlich impliziert die Regelung von Deklaratoren aber, dass das 'zeiger-sein' zum konkreten Objekt und nicht zum Typ gehört. Das finde ich tatsächlich einfach falsch (wird aber nie mehr korrigiert werden).

    Weitere Regeln sind zum Beispiel const soweit nach hinten wie möglich. Das hat auch Gründe: Schreibe ich zum Beispiel

    const class {
    ...
    } A;
    

    Dann wird ein mancher zuerst verwirrt sein.

    Call by reference gibts weder in C noch in C++ noch in Java.

    Kannst du das erläutern? Referenzen sind keine Objekte und haben daher auch keine "Werte", daher ist deine Aussage (soweit ich sehe!) völliger Unfug.



  • * und & sind Typkonstruktoren, d.h. angewendet auf einen Typen liefern sie als Ergebnis wieder einen Typen. Sie sind nicht Teil des Namens. Da hilft es auch nicht, mit "bad practise" zu argumentieren, auch wenn es die Syntax erlaubt:

    T* a, b;
    

    Persoenlich meide ich das.



  • Sone schrieb:

    daher ist deine Aussage (soweit ich sehe!) völliger Unfug.

    😞

    Sone schrieb:

    Call by reference gibts weder in C noch in C++ noch in Java.

    Kannst du das erläutern?

    Man kann kann sich überlegen ob man call by reference oder call by value hat, indem man testet, ob ein naives Swap funktioniert.

    template <class T> void naivesSwap(T a, T b){
        T c = a;
        a = b;
        b = c;
    }
    
    T a = 1, b = 2;
    naivesSwap(a, b); //geht nicht
    

    Wenn die Funktion tatsächlich swappt hat man call by reference ansonsten call by value. Wir merken dass wir call by value haben.

    template <class T> void naivesSwap(T *a, T *b){
        T c = *a;
        *a = *b;
        *b = c;
    }
    
    T a = 1, b = 2;
    naivesSwap(&a, &b); //geht
    

    Man könnte jetzt argumentieren, dass wir jetzt call by reference haben. Schließlich übergeben wir ja &a <=> Adresse von a <=> Zeiger auf a <=> Referenz auf a. Ich würde dagegen halten, dass wir ja gar kein T by reference übergeben, sondern ein T* by value.

    template <class T> void naivesSwap(T &a, T &b){
        T c = a;
        a = b;
        b = c;
    }
    
    T a = 1, b = 2;
    naivesSwap(a, b); //geht
    

    Genauso wie bei den Pointern könnte man argumentieren, dass direkt a und b übergeben werden. In der Funktion steht, dass man gern ein T & <=> T als Referenz haben möchte. Ich hingegen würde sagen es wird wieder kein T als Referenz übergeben, sondern ein T & als Wert. Beim Aufruf naivesSwap(a, b) stellt der Compiler fest, dass er ein T mit einem T & matchen soll. Er konvertiert/generiert ein T & aus einem T, damit die Funktion überhaupt aufrufbar ist. Ich übergebe also gar kein T, sondern ein T&.

    Je mehr ich darüber nachdenke, desto mehr finde ich, dass beide Ansichten dasselbe mit anderen Worten beschreiben. Ich finde aber die call by value-Sicht einfacher, denn sie hat einfachere Regeln. Immer call by value, keine Ausnahme. Mal call by reference und mal call by value ist schwer, insbesondere weil man bei T * immer verwirrt ist welches es nun ist, insbesondere wenn T ein Pointer ist.

    Sone schrieb:

    Referenzen sind keine Objekte und haben daher auch keine "Werte"

    Referenzen sind genauso "Objekte" wie Pointer auch. Sie sind keine Objekte im Sinne von Klassen, aber sie sind Objekte im Sinne von Builtin-Typen. Und sie haben natürlich einen Wert, nämlich das Objekt, dass sie Referenzieren. Sonst wären ja alle Referenzen identisch.


  • Mod

    Referenzen sind genauso "Objekte" wie Pointer auch. Sie sind keine Objekte im Sinne von Klassen, aber sie sind Objekte im Sinne von Builtin-Typen.

    Wo hast du das denn her? Referenzen sind keine Objekte, völlig unabhängig davon, wie sie implementiert sind usw.!
    Ich spreche hier auch nicht als Standard-Anbeter, aber sie haben tatsächlich kaum Eigenschaften gemein. Objekte beleben Speicher; Referenzen müssen das nicht und haben auch keine Adresse.
    Das ist schon der fundamentalste Unterschied. call-by-reference heißt mMn., du übergibst einen Verweis auf ein Objekt, welches dann in einem fremden Code verändert wird.

    Man könnte jetzt argumentieren, dass wir jetzt call by reference haben. Schließlich übergeben wir ja &a <=> Adresse von a <=> Zeiger auf a <=> Referenz auf a. Ich würde dagegen halten, dass wir ja gar kein T by reference übergeben, sondern ein T* by value.

    Das ist aber bei dem Verhalten nicht richtig. Schließlich werden die Pointees getauscht. Daher übergeben wir den Zeiger als ein Verweis, und nicht bloß als ein Skalar. Du hast schon Recht, das gerade hier ja ein Objekt übergeben wird, dann ist das vielleicht auch call by value, aber schließlich greifst du auf die Pointees zu. Irgendwie hat die Funktion ja einen Verweis.

    Er konvertiert/generiert ein T & aus einem T, damit die Funktion überhaupt aufrufbar ist. Ich übergebe also gar kein T, sondern ein T&.

    Nene. Du kannst an das Funktionstemplate ohne explizite Argumenangabe nur ein lvalue übergeben*. Die lvalue-Referenz wird dann mit diesem lvalue initialisiert. Da wird nichts generiert oder konvertiert, und was die Referenz intern macht geht uns nichts an und ist auch völlig unspezifiziert.

    * ~oder eine Klasse, die einen Konvertierungsoperator bereitstellt, der eine lvalue-Referenz zurückgibt, fast dasselbe~

    P.S.: Wieso zitieren mich alle weiterhin als Sone? :p



  • Important note: Even though a reference is often implemented using an address in the underlying assembly language, please do not think of a reference as a funny looking pointer to an object. A reference is the object. It is not a pointer to the object, nor a copy of the object. It is the object.

    http://www.parashift.com/c++-faq/overview-refs.html

    Referenzen müssen das nicht und haben auch keine Adresse.

    Wende ich den Adressoperator an, dann bekomme ich eine Adresse.

    Das ist schon der fundamentalste Unterschied. call-by-reference heißt mMn., du übergibst einen Verweis auf ein Objekt, welches dann in einem fremden Code verändert wird.

    Nein, ich uebergebe DAS Objekt und keine Kopie/Wert/Value. DAS Objekt wird bearbeitet und nicht die Kopie/Wert/Value.

    P.S.: Wieso zitieren mich alle weiterhin als Sone?

    Weil du Sone bist und dich immernoch so verhaeltst. Siehe dieses Beispiel.


  • Mod

    Wende ich den Adressoperator an, dann bekomme ich eine Adresse.

    Kannst du diese dummen Binsenweisheiten lassen? Eine Referenz hat keine Adresse, das ist ganz klar und unumstritten.

    Nein, ich uebergebe DAS Objekt und keine Kopie/Wert/Value. DAS Objekt wird bearbeitet und nicht die Kopie/Wert/Value.

    Du übergibst ein lvalue an die Funktion, so einfach ist das. Ein lvalue ist ein Ausdruckstyp, lvalues verweisen auf Objekte und Funktionen. Syntaktisch übergibst du zwar ohne Drumherum. die unqualified-id ist aber ein Ausdruck der ein Objekt designiert.
    Und natürlich bearbeitest du das Objekt selbst und keine Kopie. Das ist nur evident.



  • Sone schrieb:

    Wende ich den Adressoperator an, dann bekomme ich eine Adresse.

    Kannst du diese dummen Binsenweisheiten lassen? Eine Referenz hat keine Adresse, das ist ganz klar und unumstritten.

    Kannst du diese dummen Binsenweisheiten lassen? Eine "Referenz" ist vielleicht kein Objekt, aber sie hat ganz sicher eine Adresse.


  • Mod

    unqualified user schrieb:

    Kannst du diese dummen Binsenweisheiten lassen?

    Wäre es eine Binsenwahrheit, wäre sie zumindest einmal wahr (das ist meine Aussage ohnehin). Aber du bestreitest es gar im nächsten Satz:

    Eine "Referenz" ist vielleicht kein Objekt, aber sie hat ganz sicher eine Adresse.

    Nein! Aber wieso sage ich das zum x-ten mal?



  • unqualified user schrieb:

    Kannst du diese dummen Binsenweisheiten lassen? Eine "Referenz" ist vielleicht kein Objekt, aber sie hat ganz sicher eine Adresse.

    Ausser sie wird rausoptimiert. Oder der Compiler ist anderweitig schlau indem er das Objekt direkt an der richtigen Stelle im Stack konstruiert hat.



  • knivil schrieb:

    * und & sind Typkonstruktoren, d.h. angewendet auf einen Typen liefern sie als Ergebnis wieder einen Typen. Sie sind nicht Teil des Namens. Da hilft es auch nicht, mit "bad practise" zu argumentieren, auch wenn es die Syntax erlaubt:

    T* a, b;
    

    Persoenlich meide ich das.

    Schoen, dass wenigstens einer hier funktional programmiert und die Konzepte verstanden hat.

    Zu Mehrfachdefinitionen: Absolut kein Problem:

    int* p, * q;
    


  • Eine Referenz hat keine Adresse, das ist ganz klar und unumstritten.

    Nun, es gibt nicht umsonst FAQs. was ist so schwer an:

    It is the object.


  • Mod

    Various features of the language, such as references and virtual functions, might involve additional memory locations that are not accessible to programs but are managed by the implementation.

    Ihr meint also, dass die Implementierung der Referenz für diese Speicher belegt, welcher dann ein erstes Byte hat, wessen Adresse man dann mit der Adresse der Referenz gleichsetzen kann? Tja, das wäre sehr vage.

    Edit: Und man sollte nicht die Adresse der Referenz mit der Adresse des Objektes gleichsetzen. Die Adresse, die der Adressoperator da zurückgibt, ist immer die Adresse des referenzierten Objektes.



  • Edit: Und man sollte nicht die Adresse der Referenz mit der Adresse des Objektes gleichsetzen. Die Adresse, die der Adressoperator da zurückgibt, ist immer die Adresse des referenzierten Objektes.

    Du hast immer noch nicht verstanden. Eine Referenz ist nicht vom eigentlichen Objekt unterscheidbar:

    It is the object.

    PS: Diskutiere doch mit dem Autor des FAQs weiter.



  • Das Rausoptimieren ist doch kein Argument, das passiert bei Pointern und Integern auch.
    Ich verstehe auch nicht was mit "Man übergibt ein lvalue an die Funktion" gemeint ist. Kann doch auch ein rvalue sein. Ist auch völlig egal.*

    call-by-reference heißt meine Meinung nach "du übergibst einen Verweis auf ein Objekt, welches dann in einem fremden Code verändert wird."

    Der Knackpunkt ist wer es tut. Ist es in der Sprache definiert, dass bei Übergabe eines Objektes tatsächlich eine Referenz übergeben wird oder wird das Objekt kopiert? Selber eine Referenz anlegen und übergeben ist kein call by reference.

    Referenzen belegen natürlich Speicher, der festlegt, auf welches Objekt sich die Referenz bezieht. Genauso wie der Mechanismus hinter virtuellen Funktionen, der entscheidet, welche Funktion tatsächlich aufgerufen wird. Und genauso wie bei Referenzen kommt man nicht standardkonform an diesen Speicher. Was das Ganze mit "ist eine Referenz ein Objekt?" zu tun hat entgeht mir auch. Reine Auslegungs-/Definitions-sache ohne Konsequenzen. Aber gut, das ist call by reference vs call by value auch :p

    *~@Sone: Hier kannst du sehen wie man die Leute nicht mit "Du schreibst völligen Unfug" anpisst.~


  • Mod

    Referenzen belegen natürlich Speicher

    Woher weißt du das?

    Ich verstehe auch nicht was mit "Man übergibt ein lvalue an die Funktion" gemeint ist.

    Man übergibt an die Funktion einen Ausdruck. Ausdrücke werden bekanntlich unterteilt in lvalues und rvalues.

    Selber eine Referenz anlegen und übergeben ist kein call by reference.

    Wieso nicht?

    Was das Ganze mit "ist eine Referenz ein Objekt?" zu tun hat entgeht mir auch.

    Mir auch. Mittlerweile geht es lediglich um die Adresse.

    Diskutiere doch mit dem Autor des FAQs weiter.

    Wenn er mir nicht zustimmt, dass es streng genommen nicht stimmt, dann hab ich keine Gründe, das zu tun.

    Hier kannst du sehen wie man die Leute nicht mit "Du schreibst völligen Unfug" anpisst.

    Es tut mir Leid. Aber call-by-reference gibt es in C++, und wer etwas anderes behauptet der provoziert nur terminologisches Gerede.



  • Arcoth schrieb:

    Es tut mir Leid. Aber call-by-reference gibt es in C++, und wer etwas anderes behauptet der provoziert nur terminologisches Gerede.

    Der einzige, der hier "terminologisches Gerede" provoziert, bist du. Du bist derjenige, der andauernd mit Standard-Quotes klugscheisst.
    In der realen Welt interessiert sich niemand fuer den idealisierten C++-Standard. Dort brauchen Referenzen naemlich Speicher, wenn sie nicht wegoptimiert werden, weil sie naemlich Zeiger sind.



  • Wenn er mir nicht zustimmt, dass es streng genommen nicht stimmt, dann hab ich keine Gründe, das zu tun.

    Wenn du also nicht seiner Meinung bist, dann willst du nicht mit ihm reden. Aber wenn du seiner Meinung bist, dann gibt es keinen Grund fuer eine Diskussion. Ergo: In beiden Faellen wirst du nicht mit ihm reden. Deine Argumentation ist echt Bullshit.

    Ansonsten: Wie unterscheidet sich eine Referenz auf ein Objekt vom eigentlichen Objekt? Und was ist dann eine Referenz von einer Referenz? Und warum sollte der Typkonstruktor & sich bei Anwendung auf Objekten anders verhalten als bei Referenzen? Warum kann ich dann Referenzen nicht neu zuweisen? Rein logisch gesehen gibt es Probleme, wenn Objekt und Referenz semantisch verschieden ist.


  • Mod

    knivil schrieb:

    Wenn er mir nicht zustimmt, dass es streng genommen nicht stimmt, dann hab ich keine Gründe, das zu tun.

    Wenn du also nicht seiner Meinung bist, dann willst du nicht mit ihm reden. Aber wenn du seiner Meinung bist, dann gibt es keinen Grund fuer eine Diskussion. Ergo: In beiden Faellen wirst du nicht mit ihm reden. Deine Argumentation ist echt Bullshit.

    Gut, nicht mit ihm zu diskutieren ist keine Lösung. Wenn er tatsächlich der Überzeugung ist, das Referenzen völlig äquivalent zum Objekt sind, dann würde ich ihn gerne in einer Diskussion anders stimmen. Besser? 🙂

    Ansonsten: Wie unterscheidet sich eine Referenz auf ein Objekt vom eigentlichen Objekt?

    Die Referenz kann ungültig werden. Ein Objekt kann es nicht. Die Größe einer Referenz ist nicht einheitlich. Die des Objektes schon.

    struct A
    {
        std::string& str;
    };
    // Was ist sizeof(A)? Was ist die Summe der Größen der Member? Wäre das anders, wenn du stattdessen einen std::string als Member hast?
    

    Und was ist dann eine Referenz von einer Referenz?

    Gibt es nicht, ist mMn. auch Schwachsinn.

    Und warum sollte der Typkonstruktor & sich bei Anwendung auf Objekten anders verhalten als bei Referenzen?

    Weil du das && schon für eine rvalue-Referenz brauchst.

    Warum kann ich dann Referenzen nicht neu zuweisen?

    Weil es AFAICS keinen vernünftigen Weg gibt, das syntaktisch zu symbolisieren. Die Referenz soll ja ein neuer Name für ein Objekt sein, und sich von diesem praktisch nicht mehr unterscheiden lassen.

    Rein logisch gesehen gibt es Probleme, wenn Objekt und Referenz semantisch verschieden ist.

    Da gebe ich dir Recht, sie sollten sich semantisch völlig gleich verhalten.

    Der einzige, der hier "terminologisches Gerede" provoziert, bist du.

    Kann gut sein. Einer ist es zumindest. Was mich bei dem Post gestört hat, ist lediglich, dass Referenzen nicht einfach irgendwelche Werte sind, die kopiert werden, und das call-by-reference einfach eine Bezeichnung für Referenzen als Parameter ist.



  • keinen vernünftigen Weg gibt, das syntaktisch zu symbolisieren

    Doch gibt es. Aber du klebst zu sehr an Syntax und Implementation. Referenz von Referenz kann gern durch & & repraesentiert werden. Bitte nicht mit && verwechseln. Weiterhin existieren Referenzen schon vor C++11, d.h. && als Argument ist Schwachsinn.

    Gibt es nicht, ist mMn. auch Schwachsinn.

    Doch gibt es. Es ist nur nicht das, was du denkst.

    Die Referenz kann ungültig werden.

    Wie unterscheidet sich das von UB?


Anmelden zum Antworten