Funktionen



  • Nexus schrieb:

    float Distance(const Point& Left, const Point& Right)
    {
        return Norm(Left - Right);
    }
    

    Was soll dein Norm machen?

    wenn schon dann find ich das toller ^^

    float Distance(Point Left, const Point& Right)
    {
        Left -= Right;
        return Dotproduct(Left, Left); //Kreuzprodukt mit sich selbst
    }
    

    bb



  • unskilled schrieb:

    Was soll dein Norm machen?

    Die Länge eines Vektors zurückgeben. 😉

    unskilled schrieb:

    wenn schon dann find ich das toller ^^

    float Distance(Point Left, const Point& Right)
    {
        Left -= Right;
        return Dotproduct(Left, Left); //Kreuzprodukt mit sich selbst
    }
    

    Hm, mir gefällt nur schon die Signatur nicht. Ein Parameter als Kopie und ein anderer als Const-Referenz, obwohl beide gleichwertig sind - naja. Wieso beharrst du eigentlich so auf deinen arithmetischen Zuweisungsoperatoren? 🙂

    Zudem müsstest du noch die Wurzel aus dem Skalarprodukt ziehen...



  • Nexus schrieb:

    Hm, mir gefällt nur schon die Signatur nicht. Ein Parameter als Kopie und ein anderer als Const-Referenz, obwohl beide gleichwertig sind - naja.

    Es ist nun mal unsinnig beide als referenz zu übernehmen und dafür nen neues objekt zu erzeugen - die signatur ist nun mal so... ^^

    Nexus schrieb:

    Wieso beharrst du eigentlich so auf deinen arithmetischen Zuweisungsoperatoren? 🙂

    Weils effektiver ist!? ^^
    Und keinerlei Nachteile hat außer vll die ungewohnte Signatur ^^

    Nexus schrieb:

    Zudem müsstest du noch die Wurzel aus dem Skalarprodukt ziehen...

    Verdammt -.- Wie peinlich - mehr Fehler konnte man ja gar nicht mehr da reinmachen ^^

    bb



  • unskilled schrieb:

    Nexus schrieb:

    Hm, mir gefällt nur schon die Signatur nicht. Ein Parameter als Kopie und ein anderer als Const-Referenz, obwohl beide gleichwertig sind - naja.

    Es ist nun mal unsinnig beide als referenz zu übernehmen und dafür nen neues objekt zu erzeugen - die signatur ist nun mal so... ^^

    Finde ich auch, dass es nun mal Geschmackssache ist. Ist ja dasselbe, wie beim swap, ob da auch gleich per Kopie übergeben werden soll oder intern erzeugt.
    Soll jeder so machen, wie will (oder vorgegeben).



  • Danke für die Zustimmung, aber:

    drakon schrieb:

    Ist ja dasselbe, wie beim swap, ob da auch gleich per Kopie übergeben werden soll oder intern erzeugt.

    wie soll nen swap mit ner Kopie des/der Werte(s) funktionieren? Oo

    bb



  • unskilled schrieb:

    Danke für die Zustimmung, aber:

    drakon schrieb:

    Ist ja dasselbe, wie beim swap, ob da auch gleich per Kopie übergeben werden soll oder intern erzeugt.

    wie soll nen swap mit ner Kopie des/der Werte(s) funktionieren? Oo

    bb

    Sorry, meinte den =-Operator. Dort wird ja normalerweise eine cont Ref. übergeben und dann ein lokales Objekt damit erzeugt und geswapt. Und da kann man auch direkt die Übergabe per Kopie machen und dann mit dem swapen.



  • drakon schrieb:

    Sorry, meinte den =-Operator. Dort wird ja normalerweise eine cont Ref. übergeben und dann ein lokales Objekt damit erzeugt und geswapt. Und da kann man auch direkt die Übergabe per Kopie machen und dann mit dem swapen.

    Macht ihr das wirklich immer so?
    Was spricht dagegen, es nicht über den swap weg zu implementieren?

    bb



  • unskilled schrieb:

    drakon schrieb:

    Sorry, meinte den =-Operator. Dort wird ja normalerweise eine cont Ref. übergeben und dann ein lokales Objekt damit erzeugt und geswapt. Und da kann man auch direkt die Übergabe per Kopie machen und dann mit dem swapen.

    Macht ihr das wirklich immer so?
    Was spricht dagegen, es nicht über den swap weg zu implementieren?

    bb

    Wie gesagt. Geschmackssache (abgesehen von Optimierungen). Ich persönlich mache es eigentlich so, dass ich eine lokale Kopie erzeuge und dann damit swape.
    Afaik kommt schlussendlich sowieso das gleiche raus nach dem compilen. (zumindest bei modernen Compilern).



  • unskilled schrieb:

    Was spricht dagegen, es nicht über den swap weg zu implementieren?

    Was spricht denn dafür, Copy-Konstruktor und Destruktor doppelt zu implementieren?



  • Wieso lautet dein Benutzername theo?



  • fdsa schrieb:

    unskilled schrieb:

    Was spricht dagegen, es nicht über den swap weg zu implementieren?

    Was spricht denn dafür, Copy-Konstruktor und Destruktor doppelt zu implementieren?

    1. verschrieben 😛 DTor->CTor nehm ich mal an ^^
    2. war die ganze zeit von der swap fkt ausgegangen die man idR für die nachfolgende spezialisierung von std::swap implementiert - aber ihr nennt die init-fkt ja auch immer swap ^^

    bb



  • unskilled schrieb:

    1. verschrieben 😛 DTor->CTor nehm ich mal an ^^

    Nein, ich hab mich mich verschrieben. Wenn man den Zuweisungs-Operator nicht mit copy&swap macht, implementiert man nochmal genau das, was man in Destruktor und Copy-Konstruktor schonmal gemacht hat.



  • fdsa schrieb:

    unskilled schrieb:

    1. verschrieben 😛 DTor->CTor nehm ich mal an ^^

    Nein, ich hab mich mich verschrieben. Wenn man den Zuweisungs-Operator nicht mit copy&swap macht, implementiert man nochmal genau das, was man in Destruktor und Copy-Konstruktor schonmal gemacht hat.

    Also ich habe im =-Operator und üblicherweise 3 Zeilen:

    X::operator = (const X &rhs)
    {
       Destruct();
       Init(/*ggf parameter*/);
       return *this;
    }
    
    X::X (const X &rhs)
    {
       Init(/*ggf parameter*/);
    }
    
    X::~X () throw()
    {
       Destruct();
    }
    

    Der einzige Unterschied ist eben, dass die Zuweisung bei einer Exception das alte Objekt löscht und das neue dann halt noch nicht konstruiert ist - aber imho ist das kein Nachteil...

    bb



  • unskilled schrieb:

    Also ich habe im =-Operator und üblicherweise 3 Zeilen:

    X::operator = (const X &rhs)
    {
       Destruct();
       Init(/*ggf parameter*/);
       return *this;
    }
    
    X::X (const X &rhs)
    {
       Init(/*ggf parameter*/);
    }
    
    X::~X () throw()
    {
       Destruct();
    }
    

    Der einzige Unterschied ist eben, dass die Zuweisung bei einer Exception das alte Objekt löscht und das neue dann halt noch nicht konstruiert ist - aber imho ist das kein Nachteil...

    Nein Nein Nein Nein.
    Leben wir noch im Jahre 1998?

    Der op= sieht immer so aus:

    T const& operator=(T const& other) {
      T temp(other);
      swap(temp);
      return *this;
    }
    

    Keine Exception Sicherheit ist immer ein Nachteil. Wenn der op= naehmlich wirft ist dein Objekt kaputt. Alle Daten sind verloren. Das ist schlecht. Sehr schlecht sogar. Deshalb hat Gott uns Transaktionen geschenkt und Stroustrup hat sie uns in Form von Copy & Swap ermoeglicht.

    PS:
    die Init Funktion ist ja richtig 1998...



  • Wenn eine exception beim =-op geworfen wird, kannst du iA eh nicht darauf reagieren... (oder fällt dir nen sinnvolles Bsp ein?)
    Und warum soll eine Zuweisung 3mal so lange brauchen wie man sie normalerweise implementieren könnte?

    die Init Funktion ist ja richtig 1998...

    Sie hilft einfach mal die Übersicht zu wahren und nicht zu letzt Code-Duplikationen zu vermeiden. Ich weiß ja nicht, was du bis zum nächsten Standard machst - aber ich kann bis dahin keinen CTor in nem anderen aufrufen - und deshalb bleibt nun mal nur den Ausweg mit Init()

    bb



  • unskilled schrieb:

    float Distance(float x1, float y1, float z1, float x2, float y2, float z2) 
    {
        x1 -= x2;
        y1 -= y2;
        z1 -= z2;
        const float distance_square = x1*x1 + y1*y1 + z1*z1;
        return static_cast <float> sqrt(distance_square); 
    }
    

    Schreib doch gleich alles in Assembler :p
    Kann dein Compiler keine mehrfach verwendeten Teilausdrücke eliminieren? Das ist eigentlich eine Standardtechnik ... dann kommt in der lesbaren und in der 'optimierten' Version auch der gleiche Code raus.



  • vermutlich kann er das, weil er von MS ist 🤡
    aber ich denke nicht, dass er den -= operator nutzen würde - ich tippe mal auf den - operator... aber bin gerade zu faul das zu testen - vll hat ja nen anderer mehr lust und kann besser asm als ich das kann ; D

    bb



  • unskilled schrieb:

    vermutlich kann er das, weil er von MS ist 🤡
    aber ich denke nicht, dass er den -= operator nutzen würde - ich tippe mal auf den - operator... aber bin gerade zu faul das zu testen - vll hat ja nen anderer mehr lust und kann besser asm als ich das kann ; D

    du weisst schon dass es bei primitiven datentypen keinen unterschied zwischen - und -= gibt, oder?

    wenn der compiler hier nicht richtig optimiert, dann stimmt etwas nicht.

    merke: immer zuerst schoen und korrekt programmieren und _dann_ erst an performance denken wenn der profiler es dir gesagt hat.



  • Shade Of Mine schrieb:

    das hier ist zB premature optimization die nichts bringt.

    genau.
    und weil premature optimization mein hobby ist, zeige ich mal, wie das richtig geht:

    float Distance(float x1, float y1, float z1, float x2, float y2, float z2) 
    { 
        return sqrt(DistanceSquare(x1,y1,z1,x2,y2,z2); 
    }
    //und damit das klappt, braucht man noch
    float DistanceSquare(float x1, float y1, float z1, float x2, float y2, float z2)
    {
       return Square(x2-x1)+Square(y2-y1)+Square(z2-z1);
    }
    //und damit das klappt, braucht man noch
    float Square(float x)
    {
       return x*x;
    }
    


  • unskilled schrieb:

    Es ist nun mal unsinnig beide als referenz zu übernehmen und dafür nen neues objekt zu erzeugen - die signatur ist nun mal so... ^^

    Naja, wie gesagt Geschmackssache. Aber eigentlich kommt es schlussendlich nicht so drauf an.

    unskilled schrieb:

    Weils effektiver ist!? ^^
    Und keinerlei Nachteile hat außer vll die ungewohnte Signatur ^^

    Naja, ich würde es trotzdem eher so machen. Das temporäre Objekt ( Left - Right ) kann womöglich wegoptimiert werden.

    float Distance(const Point& Left, const Point& Right) 
    { 
        Point DistanceVec = Left - Right; 
        return Dotproduct(DistanceVec, DistanceVec);
    }
    

    unskilled schrieb:

    Macht ihr das wirklich immer so?
    Was spricht dagegen, es nicht über den swap weg zu implementieren?

    Zum Beispiel Exceptionsicherheit und Codeduplizierung. Siehe auch diesen Thread.


Anmelden zum Antworten