Referenzen in Klassen



  • Hallo,

    gibt es eigentlich einen vernünftigen Grund warum Referenzen nicht kopierbar sind?

    Ich habe viele kopierbare Klassen, die als member "Referenzen" auf andere Klassen halten.
    Da kann man dann entweder Pointer (unschön, weil dann nicht klar ist, ob das ganze nicht doch NULL sein kann und wegen Konvertierung der Argumente) oder std::reference_wrapper<T> (unschön, weil zu lang/unleserlich, unbekannt und wegen Konvertierung der Argumente) verwenden. 😞
    Wie geht ihr damit um?



  • Ich habe viele kopierbare Klassen, die als member Referenzen auf andere Klassen halten.

    Ich habe keine Referenzen als Member. Ist viel zu problematisch bspw. bei Kopier- oder Move-Konstruktor/Operator. Oder Zuweisungen: Veraendern auch andere Objekte.

    Ich habe viele kopierbare Klassen, die als member Referenzen auf andere Klassen halten.

    Wie unterscheidest du tiefe und flache Kopie?

    Da kann man dann entweder Pointer ...

    Da fehlt das Hauptverb.



  • C14 schrieb:

    gibt es eigentlich einen vernünftigen Grund warum Referenzen nicht kopierbar sind?

    Sie sind kopierbar, sonst könntest du keine Referenzen an Funktionen übergeben. Sie sind aber nicht zuweisbar, weil sie bei der Definition initialisiert werden und nachher nicht mehr verändert werden können. Genau wie const -Variablen.

    C14 schrieb:

    Wie geht ihr damit um?

    Zeiger nehmen, wenn Referenzen zu unflexibel sind. Sicher nicht std::reference_wrapper .



  • Referenzen als Klassenelemente sind eigentlich nur dann praktisch, wenn man eine Klasse schreibt, die sich selbst so wie eine Referenz verhalten soll. Zumindest wird der Compiler in dem Fall keinen Zuweisungsoperator automatisch generieren. Und das ist in dem Fall ja auch gut so, da man die Zuweisungen bei solchen "Referenz-Proxies" eh selbst händeln muss.

    reference_wrapper<> dagegen ist ein komischer Mix aus C++ Referenz und Zeiger, vom Verhalten her...


  • Mod

    Sicher nicht std::reference_wrapper.

    Das ist dafür auch nicht gedacht. Sondern bspw. für Container, oder als Funktor-Wrapper.



  • edit: Ich sehe ein, dass das deep copy Verhalten für Referenzen als default Sinn macht 🙂

    In meinem Fall sind die referenzierten Objekte aber quasi singletons oder haben zumindest eine hohe Lebenszeit.
    Es sind service Objekte die zum Teil Betriebssystemresourcen kapseln. (z.B. threadpool, logger, tempfile-manager)

    Bei einer Kopie des Objekts sollen diese Abhängigkeiten nur flach kopiert werden.

    Es ist legacy code und aktuell wird es mit Zeigern gemacht.
    Da schlecht dokumentiert ist, bei welchen davon null erlaubt ist, wird oft unnötig auf null geprüft.
    Was spricht da gegen std::reference_wrapper?



  • Arcoth schrieb:

    Sicher nicht std::reference_wrapper.

    Das ist dafür auch nicht gedacht.

    Wer definiert, wofür reference_wrapper gedacht ist?

    Sondern bspw. für [den Einsatz in einem] Container,

    Wo ist da der Unterschied zu Pointern?

    oder als Funktor-Wrapper.

    Ein Wrapper um Funktor? (Ja, schon klar, wie das gemeint ist)

    krümelkacker schrieb:

    reference_wrapper<> dagegen ist ein komischer Mix aus C++ Referenz und Zeiger, vom Verhalten her...

    reference_wrapper<> ist ein Non-Null-Pointer, wo ist da ein Komiker?


  • Mod

    Wo ist da der Unterschied zu Pointern?

    Stellst du dich doof?

    reference_wrapper<> ist ein Non-Null-Pointer

    Ein Wrapper um Funktor?

    Nein, ein Zirkusclown.

    (Ja, schon klar, wie das gemeint ist)

    Wieso fragst du dann?



  • Es ist legacy code und aktuell wird es mit Zeigern gemacht.

    Ich benutze auch in Nicht-Legacy-Code noch viele rohe Zeiger. Warum willst du sie mit ersetzen? Nur um die Tests auf Null zu entfernen? Der Aufwand lohnt wahrscheinlich nicht.



  • wortanalyse schrieb:

    krümelkacker schrieb:

    reference_wrapper<> dagegen ist ein komischer Mix aus C++ Referenz und Zeiger, vom Verhalten her...

    reference_wrapper<> ist ein Non-Null-Pointer, wo ist da ein Komiker?

    Ein Non-Null-Pointer, der sich zum Teil wie eine Referenz verhält, mit Ausname des Zuweisungsoperators:

    #include <functional>
    
    using std::reference_wrapper;
    
    struct fu
    {
        void operator()(int) const {}
    };
    
    void foo(int&) {}
    
    void bar()
    {
        int i = 23;
        reference_wrapper<int> r = i; // <-- Initialisierung wie eine Referenz
        foo(r);                       // <-- Keine Dereferenzierung nötig
    
        fu o;
        reference_wrapper<fu> w = o;  // <-- Initialisierung wie eine Referenz
        w(23);                        // <-- Keine Dereferenzierung nötig
        fu *ptr = &o;
        ptr(24);                      // <-- Funzt nicht ohne Dereferenzierung
    }
    

    Es bietet also eine implizite Lvalue of T -> reference_wrapper<T> als auch eine implizite reference_wrapper<T> -> Lvalue of T Konvertierung an.

    Komisch ist dieses Verhalten meiner Meinung nach in Verbindung mit dem Zuweisungsoperator.

    void wtf()
    {
        int i = 23;
        reference_wrapper<int> x = i; // x bezieht sich auf i.
        int j = x;                    // j hat den gleichen Wert wie i.
        x = j;                        // x bezieht sich jetzt auf j statt dass
                                      // der Wert von j nach i kopiert wird.
    }
    

    Im Übrigen heißt das Ding nicht pointer_wrapper .


Anmelden zum Antworten