Pitfalls C++11



  • Was glaubt ihr, dass C++11 an Fallstricken hat?

    Ich glaube das übermäßige Verwendung von "auto" zu einigen ungewollten Bugs führen könnte.



  • Wenn es um den Glauben geht, bist du in der Kirche besser aufgehoben als bei C++.



  • Ein Problem, das ich mit auto sehe, sind Proxyobjekte.

    auto i = threadsafe_ptr->foobar(); // operator -> gibt einen Proxy zurück, der im Ctor lockt und im Dtor unlockt
    


  • 314159265358979 schrieb:

    Ein Problem, das ich mit auto sehe, sind Proxyobjekte.

    auto i = threadsafe_ptr->foobar(); // operator -> gibt einen Proxy zurück, der im Ctor lockt und im Dtor unlockt
    

    Und?



  • Meh, okay. In dem Fall funktionierts sogar. Aber man denke nur an Expression Templates.



  • 314159265358979 schrieb:

    Meh, okay. In dem Fall funktionierts sogar. Aber man denke nur an Expression Templates.

    Und?



  • Ach, vergesst es. Ihr wisst genau was ich meine und bestimmt kommt auf den nächsten 2-3 Seiten genau dasselbe von wem anderen, wo natürlich nichts hinterfragt wird.



  • Nein, ich hab wirklich absolut keine Ahnung was du meinst 😕





  • Idealerweise geben die Operationen aber auch bei Expression Templates den Zieltyp und nicht die Operation zurück:

    my_complex operator + (my_complex const& lhs, my_complex const& rhs)
    {
            return my_complex(addition(lhs, rhs));
    }
    


  • Das würde doch den Sinn von Expression Templates vernichten? 😕



  • 314159265358979 schrieb:

    Das würde doch den Sinn von Expression Templates vernichten? 😕

    RVO und so? Ich habe noch nie Porduktivimplenetierungen gesehen, wo die Operation zurückgegeben wurde.



  • Der Sinn von Expression Templates ist doch Lazy Evaluation, oder etwa nicht?



  • 314159265358979 schrieb:

    Der Sinn von Expression Templates ist doch Lazy Evaluation, oder etwa nicht?

    Ne, der Sinn von Expressiontemplates ist es, Temporaries zu vermeiden.



  • Das kann aber schon mein Compiler, dazu brauche ich keine Expression Templates. 🙄



  • 314159265358979 schrieb:

    Das kann aber schon mein Compiler, dazu brauche ich keine Expression Templates. 🙄

    Guck Dir an, wie man es wirklich macht. Ich schätze mal, dass zum Beispiel boost.ublas oder spirit da passenden Code bereithalten. Alternativ guck Dir nochmal irgendwelche Idiomseiten am, die Expressiontemplates behandeln.

    Typischweise kann man übrigens auch bei Implementierungen die Expressiontemplates benutzen std::cout << (a + b) schreiben, und, Geheimtip, es wird dabei sinnigerweise nicht extra ein operator<< für die Operation überladen.
    Auch sowas wie a + b + c dürfte bei Deiner Implementierung schwierig werden.



  • Die Gefahr bei auto + expression templates ist, dass in einem Design, wo expression-Objekte nur als temporäre Objekte gedacht sind, die irgendwelche Verweise auf andere expression-Objekte speichern, man sich ganz schnell ungültige Zeiger/Referenzen einfangen kann, da man mit auto ja die Lebenszeit eines solchen Objekts quasi verlängern kann. Früher musste man den Typ explizit angeben und es gab ggf eine Konvertierung vom Expression-Objekt zum gewünschten Typ. Mit auto kann man nun expression-Objekte direkt halten, was ggf eine sehr schlechte Idee ist (je nach ET Design).



  • Wobei man sich fragt wo da der Fehler ist. Bei auto, oder bei einer Funktion mit einem "falschen" Rückgabewert, die einfach davon ausgeht, dass die Außenwelt schon weiß was zu tun ist.



  • krümelkacker schrieb:

    ...

    Ich verstehe durchaus, was Pi meint, und es mag durchaus Fälle geben, in denen das so implementiert ist (das englische Wikipediabeispiel macht es z.B. so). Jedoch halte ich die Lösung mit temporären Expression-Objekten für eher ungünstig, weil dies auch ohne auto durchaus zu unerwarteten Problemen führen kann. Und seine Aussage, dass die Rückgabe des konkreten Typs des Operanden die Idee hinter Expression Templates ad absurdum führt, ist einfach falsch. Mehr wollte ich eigentlich gar nicht sagen.



  • Ich sehe auch, dass Rvalue-Referenzen gerne mal missverstanden und missbraucht werden. Viel zu oft bekommt eine Funktion eine Rvalue-Referenz als Rückgabetyp verpasst. Manche verstehen einfach nicht, dass eine Rvalue-Referenz auch nur eine Art Referenz ist und dass da keine Compiler-Magie hintersteckt und plötzlich ohne das Zutun des Klassendesigners ein Objekt der Klasse "movebar" macht.

    Der größte Fallstrick in diesem Bereich ist wahrscheinlich die Sonderregel zur Template Argument Deduction:

    #include <iostream>
    
    template<class T> void foo(T const&)
    {
      std::cout << "dings!\n";
    }
    
    template<class T> void foo(T &&)
    {
      std::cout << "bums!\n";
    }
    
    int main()
    {
      int i = 23;
      foo(i);    // i    ist ein Lvalue
      foo(i+0);  // i+0  ist ein Rvalue
    }
    

    Was ist wohl die Ausgabe dieses Programms? Wer hier erwartet, dass das Programm irgendwann mal "dings!" ausgibt, liegt nämlich falsch. Im ersten Fall wird für das zweite Template T=int& deduziert und da dann T&&=int& gilt, nimmt die Funktion eine non-const Lvalue-Ref auf int und ist damit ein besser Match (da kein const). Warum gibt's diese Deduktionsregel, die hier zu T=int& führt? Damit "perfect forwarding" funktioniert.


Anmelden zum Antworten