Klassen verständniss



  • aber mit getKennzKopie spart man drei Zeichen beim tippen.

    test(a.getKennzKopie());
    test(string(a.getKennz()));
    

    auch ein netter vorschlag, damit kopiegetter nicht immer eingebaut werden müssen:

    template<typename T>
    T kopie(T const& t){
       return t;
    }
    test(kopie(a.getKennz()));
    

    mann, bin ich heute wieder fantasievoll. 🤡



  • 3 Zeichen, da fehlt ne klammer 😃

    grrrr - hat er doch noch schnell nachgezählt 😉



  • Knuddlbaer schrieb:

    Die Signatur der Funktion sagt das sie für eine Modifikation des übergebenen Parameters zuständig ist. Die vielen anderen nützlichen Dinge wären Seiteneffekte.

    Eine Funktion mit Rückgabetyp void, die Seiteneffekte verursacht; wer hätte das gedacht? 😉 Die Modifikation des übergebenen Parameters kann evtl. auch eine ignorierbare Log-Funktionalität darstellen.



  • Ich sehe hier erst einmal das Bedürfnis meine Sicht von Seiteneffekten zu erläutern um missverständnisse von flamen zu unterschieden:

    Unter Seiteneffekt verstehe ich, das die Funktion Daten verändert die nicht offensichtlich sind.

    void x::test(T & t)
    {
       // Seiteneffekte
       intern_ganz_viel_am_internen_objekt_aendern();
       t += 2;
    }
    

    Und was wenn x::test nun davon ausgeht, das t wirklich geändert wurde ?

    Drehen wir den Spieß doch mal um:

    Nenne einen konkreten Fall in dem man einer Routine, die Werte ändert und deren Implementierung unbekannt ist, eine Kopie des zu ändernden Wertes übergeben sollte und warum dies kein Risiko betreffend undefinierten Verhaltens ist.

    Ebenso wäre es interesannt Deine Sicht der Designentscheidung zu erfahren einer solchen Routine eine aufwendige und teure Kopie zu übergeben.

    Mir fällt dazu nur das ausnutzen von Seiteneffekten (s.o.) zu verwenden und die eigentliche Aufgabe der Routine wegzuwerfen.

    (Das es in der Praxis viele Routinen gibt die T & annehmen aber keine Änderung des Wertes vornehmen sei als bekannt hingestellt aber nicht als garantiert).

    Ich lerne doch gerne was neues dazu - und bitte nich als Flame verstehen



  • Knuddlbaer schrieb:

    (Das es in der Praxis viele Routinen gibt die T & annehmen aber keine Änderung des Wertes vornehmen sei als bekannt hingestellt aber nicht als garantiert).

    nee, ist mir neu.



  • Na dann von mir aus auch T * und nen Blick in die WinApi oder so macher kommerziellen Lib, den Quellcode vom Cheffe .... 🤡 In dem was zum standard gehört kann ich Dir keinen einzigen Fall nennen (weils den nich gibt oder ich mich nich auskenne mit C++)



  • Knuddlbaer schrieb:

    Na dann von mir aus auch T * und nen Blick in die WinApi oder so macher kommerziellen Lib, den Quellcode vom Cheffe .... 🤡 In dem was zum stan**** gehört kann ich Dir keinen einzigen Fall nennen (weils den nich gibt oder ich mich nich auskenne mit C++)

    in libs, die sooo alt sind, daß sie in c vor 1999 geschrieben wurden. da mögen T* vorkommen, wo T const* gemeint ist.



  • Knuddlbaer schrieb:

    Unter Seiteneffekt verstehe ich, das die Funktion Daten verändert die nicht offensichtlich sind.

    Auch jede Ausgabe ist ein Seiteneffekt obwohl sie die Daten nicht verändert.



  • volkard schrieb:

    in libs, die sooo alt sind, daß sie in c vor 1999 geschrieben wurden. da mögen T* vorkommen, wo T const* gemeint ist.

    Naja, ein Blick in das .Net Framework 2.0 :

    public: static int String::Compare (String^ strA, String^ strB);
    public: bool String::Contains (String^ value);
    

    (^ = managed Pointer)

    Ok, die definition von Seitenefekten sollte ich mir noch mal ansehen, aber der Punkt "Warum kann es sinvoll sein eine Kopie zu übergeben um ein T & zu einem T zu machen" wäre für mich vom verständnis her noch offen.

    Gerade wenn man Volkards ansprüche annimmt, das überall wo Nichts verändert wird T const(*|&|^|%) angesetzt wird erschliesst sich mir der Grund nicht und ich würde gerne diese Wissenslücke schliessen.



  • Knuddlbaer schrieb:

    Gerade wenn man Volkards ansprüche annimmt, das überall wo Nichts verändert wird T const(*|&|^|%) angesetzt wird erschliesst sich mir der Grund nicht

    Z.B. allein schon deswegen, damit dir der Compiler deinen Code um die Ohren haut,
    wenn du versuchst, eine als const definierte Variable, einer Funktion
    zu übergeben, die ihr Argument verändert.



  • Nun geht es in der Dikussion aber um folgendes konstrukt:

    void test(T &);
    void test(T(value));
    

    Also einer ändernden Funktion/Methode eine Kopie des Wertes zu übergeben, siehe ein paar Beiträge weiter vorne.

    Z.B. allein schon deswegen, damit dir der Compiler deinen Code um die Ohren haut,
    wenn du versuchst, eine als const definierte Variable, einer Funktion
    zu übergeben, die ihr Argument verändert.

    Ein Aufruf von

    test(const_cast<T>(t));
    

    verbessert die Situation von test nicht.

    test(T(t));
    

    mag das ganze zwar verbessern, aber mir erschliesst sich dennoch nicht, warum ich als Entwickler so etwas machen will - eine Kopie an eine Funktion zu übergeben deren Aufgabe die Wertänderung ist.



  • Eigentlich ist die Frage gegenstandslos.

    Die Antwort wären IMHO:

    Nach standard garnicht, funktionen die eine solche Schnitstelle liefern werden immer einen Wert ändern und in diesem Falle ist es völlig sinnfrei eine Kopie zu übergeben - ausnutzen von Seiteneffekten ist tabu.

    In der Praxís fällt mir nur eine Situation ein:

    Die Implementierung test ist unbekannt bzw. garantiert nicht das der Wert nicht geändert wird und man hat sehr empfindliche Daten, die garantiert keine Änderung erfahren dürfen und an test übergegen werden müssen.

    (Eigentlich die gleichen Gründe für einen const_cast ? Wobei der const_cast ja wiederum notwendig sein könnte um ein einer void test(T const&) const änderungen an membern zu machen !?)

    Also, Diksussion führt zu nix, lasse mers 🤡



  • Ein kleines Beispiel, wie es in einer Bibliothek aussehen könnte:

    struct verschiebung
    {
        int dx, dy;
        verschiebung(int x_ = 0, int y_ = 0) : dx(x_), dy(y_), m_istAkzeptiert(false) {}
    private:
        bool m_istAkzeptiert;
    };
    
    class sprite
    {
        int m_x, m_y;
    public:
        void verschiebe(verschiebung &v)
        {
            int x = v.dx + m_x;
            if( x <= 10 && x >= -10)
            {
                m_x = x;
                m_y += v.dy;
                v.m_istAkzeptiert = true; //manchmal kann man drauf verzichten
            }
            else
                v.m_istAkzeptiert = false; //manchmal kann man drauf verzichten
        }
    };
    

    Falls es keine brauchbare Überladung gibt und man nicht an den Quelltext drankommt und eine hinzufügen kann, könnte man sich natürlich eine Hilfsfunktion basteln, um diesen Design-Fehler zu umgehen:

    inline void verschiebeHilfe(sprite &s, const verschiebung &v)
    {
        verschiebung vhilf = v; // Kopie machen, weil es keine Überladung für const verschiebung &v gibt!
        s.verschiebe(vhilf);
    }
    

    Achso, das .NET Framework unterstützt überhaupt keine Parameter die Referenzen auf const sind.
    Die Features von C++ sind halt was besonderes 😋



  • 😮 oh ich sehe gerade, sprite braucht natürlich auch zugriffsrecht auf verschiebung::m_istAkzeptiert. kann man zum ausprobieren mit friend machen:

    struct verschiebung
    {
        friend class sprite;
        int dx, dy;
        verschiebung(int x_ = 0, int y_ = 0) : dx(x_), dy(y_), m_istAkzeptiert(false) {}
    private:
        bool m_istAkzeptiert;
    };
    


  • Nun, das erklärt die Sinnmässigkeit immer noch nicht.

    Wenn ich es ignorieren kann, kann ich auch die veränderung zu lassen. Wenn ich die Änderung nicht zulassen darf ist die Methode falsch implementiert bzw. wird nicht richtig verwendet.

    In Deinem Beispiel wird Kentniss der internen Implementierung ausgenutzt.

    Aber die Diskussion dreht sich im Kreis ;o)

    Einigen wir uns, das es Situationen gibt bei der man auch bei rot über die Ampel fahren sollte und man bei einem solchen Konstrukt wie Du es zeigst stehts vorsicht walten lassen sollte und mehrfach überlegen sollte ob die Anwendung richtig ist.

    Wenn man Einfluss auf die Implementierung hat (und die hat man wohl wenn man das wissen dergleichen ausnutzt :D) würde ich die Hilfsfunktion so implementieren:

    void verschiebe_pruefend(verschiebung &v)
        {
    		v.m_istAkzeptiert = verschiebe(v);
        }
    
        bool verschiebe(verschiebung const &v)
        {
            int x = v.dx + m_x;
            if( x <= 10 && x >= -10)
            {
                m_x = x;
                m_y += v.dy;
                return true;
            }
            else
                return false;
        }
    

    Hier umgehst Du das Problem der Kopie und bekommst nörgler wie mich zufrieden gestellt 😃

    [Edit] Ja, das Kapitel const muss ich noch mal lesen.
    const v&
    v &const
    const v const &

    etc O🤡
    [Edit]


Anmelden zum Antworten