Noch einmal const & usw.



  • dove schrieb:

    temi schrieb:

    Version 1 funktioniert, ist aber nicht optimal, weil der String bei der Übergabe kopiert wird (Performance) und der Anwender der Klasse nicht davon ausgehen kann, dass die Klasse die übergebene Variable nicht verändert (auch wenn sie es nicht tut).

    probiere *das* aus. versuche, die übergebene variable zu ändern und schau, ob das jemand von außen merkt.

    Ich habe die Klasse erweitert:

    void setName(const std::string& name)
                {
                    //name = "Ade du blöde Welt"; fehler beim compilieren => const!!!
                    this->name = name;
                }
    

    Ich habe es in allen Varianten probiert. Hat sich wie erwartet verhalten.

    Stimmt das, was ich mir hier zusammengereimt habe, oder gibt es noch etwas zu ergänzen?

    Die erste Hälfte beantworte ich mir mal mit ja. Zweite Hälfte?

    Es wird doch trotzdem noch eine Kopie des Parameters erstellt, wenn dieser an die Membervariable "name" zugewiesen wird (nicht dargestellt), oder? Ist aber auch sinnvoll in diesem Fall.

    Ist zumindest für mich so logisch, es sein den die Membervariable wäre auch & (bzw. const &), aber das ist dann vermutlich nicht sinnvoll. Richtig?

    Meine Regel wäre jetzt: Falls die Klasse den Parameter nicht verändert übergebe ich ihn als const &. Das sollte i.d.R. so der Fall sein.

    ???



  • manni66 schrieb:

    temi schrieb:

    Habe ich gemacht, während ich die einzelnen Varianten hier hinzugefügt hab.

    Nein

    Ist meine Webcam an, oder hast du hinter mir gestanden? 😮

    Sorry, ich weiß, dass du gerne zum Nachdenken anregst, aber ich steh grad auf dem Schlauch.



  • dove schrieb:

    temi schrieb:

    Version 1 funktioniert, ist aber nicht optimal, weil der String bei der Übergabe kopiert wird (Performance) und der Anwender der Klasse nicht davon ausgehen kann, dass die Klasse die übergebene Variable nicht verändert (auch wenn sie es nicht tut).

    probiere *das* aus. versuche, die übergebene variable zu ändern und schau, ob das jemand von außen merkt.

    Mach das



  • Ich glaube ich weiß, was ihr meint. Die von außen übergebene Variable kann natürlich nicht innerhalb der Funktion von Variante 1 geändert werden, weil diese nur auf die Kopie der Variablen zugreifen kann.

    Das hatte ich nicht explizit hingeschrieben und auch anders gemeint, mein Fehler.

    und der Anwender der Klasse nicht davon ausgehen kann, dass die Klasse die übergebene Variable nicht verändert (auch wenn sie es nicht tut).

    Ich hatte vorher einen Text zur "const correctness" durchgelesen und das so interpretiert, dass es guter Stil wäre den Aufrufer durch die Angabe von "const" direkt darauf hinzuweisen, dass es garantiert keine Änderung der übergebenen Variable geben wird.



  • Keine Antwort = alles richtig?



  • Ich möchte das Thema gerne noch etwas erweitern:

    class Foo
        {
            public:
                Foo(const std::string& name):name(name){};
                std::string getName()
                {
                    return name;
                }
            private:
                const std::string name;
        };
    
    class Bar
    {
        public:
            void setFoo(std::unique_ptr<Foo> pFoo)
            {
                foo = std::move(pFoo); // move wegen unique_ptr
            }
    
            std::string getName()
            {
                return foo->getName();
            }
    
        private:
            std::unique_ptr<Foo> foo;
    };
    
    int main(int argc, char *argv[])
    {
        Bar bar;
    
        auto foo = std::unique_ptr<Foo>(new Foo{"Hallo Welt"});
    
        cout << foo.get()->getName() << endl;
    
        bar.setFoo(foo); // hier ist das Problem
    
        cout << bar.getName() << endl;
    }
    
    bar.setFoo(foo);
    

    geht nicht, weil

    void setFoo(std::unique_ptr<Foo> pFoo)
    

    eine Übergabe per value ist und das funktioniert mit unique_ptr ja nicht, weil keine Kopie möglich ist.

    Also erst mal:

    void setFoo(std::unique_ptr<Foo>& pFoo)
    

    dann klappt das auch. 🙂

    Jetzt möchte ich aber auch dieses machen:

    int main(int argc, char *argv[])
    {
        Bar bar;
    
        //auto foo = std::unique_ptr<Foo>(new Foo{"Hallo Welt"});
    
        //cout << foo.get()->getName() << endl;
    
        bar.setFoo(std::unique_ptr<Foo>(new Foo{"Hallo Welt"})); // Fehler: invalid initialization of non-const reference
    
        cout << bar.getName() << endl;
    }
    

    Geändert in:

    void setFoo(const std::unique_ptr<Foo>& pFoo)
    
    void setFoo(const std::unique_ptr<Foo>& pFoo)
            {
                foo = std::move(pFoo); // Fehler: Use of deleted function...
            }
    

    Meine Erklärung wäre dazu, dass der Parameter ja const ist und damit nicht verändert werden darf. Soweit so gut. Aber wie erreiche ich jetzt mein Ziel?



  • temi schrieb:

    Keine Antwort = alles richtig?

    Hattest du 24/7 gebucht? Moment, ich schau mal nach...
    Nein, ich sehe auch keinen Zahlungseingang.



  • temi schrieb:

    und der Anwender der Klasse nicht davon ausgehen kann, dass die Klasse die übergebene Variable nicht verändert (auch wenn sie es nicht tut).

    Ich hatte vorher einen Text zur "const correctness" durchgelesen und das so interpretiert, dass es guter Stil wäre den Aufrufer durch die Angabe von "const" direkt darauf hinzuweisen, dass es garantiert keine Änderung der übergebenen Variable geben wird.

    Das wirst du wohl falsch verstanden haben.
    1. ist das dem Aufrufer völlig schnuppe
    2. kann man den const Parameter jederzeit kopieren und dann ändern



  • void setFoo(std::unique_ptr<Foo>& pFoo)
    

    Wer so etwas schreibt hat ziemlich sicher keine Ahnung.
    Entweder übernimmt setFoo den Besitz. Dann ist es keine Referenz und der Wert muss gegebenenfalls mit move reingeschoben werden.
    Oder der Besitz wird nicht übernommen. Dann wird Foo* übergeben und kein Smartpointer.



  • manni66 schrieb:

    [/code]
    Wer so etwas schreibt hat ziemlich sicher keine Ahnung.

    Natürlich habe ich keine Ahnung, sonst würde ich ja nicht fragen, oder?

    Du musst natürlich nicht nett und freundlich sein, aber ich finde es wäre kein Schaden.



  • temi schrieb:

    Aber wie erreiche ich jetzt mein Ziel?

    Was ist denn dein Ziel?



  • temi schrieb:

    Ich möchte das Thema gerne noch etwas erweitern:

    auto foo = std::unique_ptr<Foo>(new Foo{"Hallo Welt"});
        cout << foo.get()->getName() << endl;
        bar.setFoo(foo); // hier ist das Problem
    }
    
    bar.setFoo(foo);
    

    geht nicht, weil

    void setFoo(std::unique_ptr<Foo> pFoo)
    

    eine Übergabe per value ist und das funktioniert mit unique_ptr ja nicht, weil keine Kopie möglich ist.

    Wenn du foo in deiner main nicht mehr nutzen willst nach dem Call von bar.setFoo, dann musst du schreiben: bar.setFoo(move(foo)); . D.h. Übergabetyp ist der unique_ptr<Foo> (keine Referenz auf unique_ptr!). Und wenn du Ownership nicht transferieren willst, dann einfach Foo* übergeben (bzw const Foo* wenn möglich)

    Ich hatte gehofft, dass diese Fälle ziemlich deutlich in den 3 von dove und mir geposteten gotw-Links erklärt wäre.



  • wob schrieb:

    Ich hatte gehofft, dass diese Fälle ziemlich deutlich in den 3 von dove und mir geposteten gotw-Links erklärt wäre.

    Großes SORRY und auch Dank dafür! Ich hatte das natürlich (neben Vielem anderen) durchgelesen, aber irgendwie auch schon wieder verdrängt. Ist mir dann gestern, aber aufgefallen und ich habe die Lesestunde bereits wiederholt. Ich bin halt nicht mehr der Jüngste, aber irgendwann kapier ich es auch noch.

    Gruß,
    temi


Anmelden zum Antworten