RVO und günstige Konvertierung



  • Ach, mit "immer temporär" meint er, dass er z.B. nur sowas macht "new MyClass(Create())".



  • hustbaer schrieb:

    @Nexus:
    Was du schreibst ist schon richtig, war ja nur ein Vorschlag.
    Ich kann nicht wissen welche Variante bei deinem Problem besser ist: dass man die Kopie immer verhindert, dafür alles eine Spur langsamer wird, oder dass der "keine Kopie" Fall ne Spur schneller wird, dafür manchmal doch wieder kopiert werden muss.

    Ja, stimmt schon. Mir ist bewusst, dass man mit RVO immer das Risiko eingeht, dass eben doch Kopien entstehen, die alles langsam machen. Jedoch schätze ich den Anteil der Benutzer mit moderneren Compiler eher hoch ein (und mir gefällt der Gedanke irgendwie nicht, diese zu "bestrafen").

    Der Performanceverlust wäre in meinem Fall wahrscheinlich auch verkraftbar (dennoch habe ich die Frage gestellt, um generell RVO und gängige Praxis etwas besser kennenzulernen). Jedenfalls vielen Dank für die Hinweise!

    ??????? schrieb:

    Ach, mit "immer temporär" meint er, dass er z.B. nur sowas macht "new MyClass(Create())".

    Genau, daher auch meine unschöne Idee mit const_cast . Wie ist das dort eigentlich, wäre das undefiniertes Verhalten? Oder wäre das nur der Fall, wenn man const von einem benannten, const -qualifizierten Objekt wegcastet?


  • Administrator

    Nexus schrieb:

    Der Performanceverlust wäre in meinem Fall wahrscheinlich auch verkraftbar (dennoch habe ich die Frage gestellt, um generell RVO und gängige Praxis etwas besser kennenzulernen). Jedenfalls vielen Dank für die Hinweise!

    Hmmm, dürfte die gängige Praxis in dem Fall nicht eher sein, dass man beide Versionen testet, mit einem Profiler analysiert und sich dann für die beste Option für den/die eingesetzen Kompiler entscheidet? 🙂

    Nexus schrieb:

    Wie ist das dort eigentlich, wäre das undefiniertes Verhalten? Oder wäre das nur der Fall, wenn man const von einem benannten, const -qualifizierten Objekt wegcastet?

    Oder anders ausgedrückt: Wer hat Lust den Standard hervorzuholen und zu blättern? 😃

    Grüssli



  • Dravere schrieb:

    Hmmm, dürfte die gängige Praxis in dem Fall nicht eher sein [...]

    Nein.

    Da auf MSVC++ und g++ die Kopie wegoptimiert wird, ist es sicher schneller als mit shared_ptr . Um das zu wissen, muss ich keinen Profiler bemühen.

    Abgesehen davon deutet mein "generell" darauf hin, dass es nicht nur um den speziellen Fall hier geht.


  • Administrator

    Nexus schrieb:

    Da auf MSVC++ und g++ die Kopie wegoptimiert wird, ist es sicher schneller als mit shared_ptr . Um das zu wissen, muss ich keinen Profiler bemühen.

    Unter Profiler habe ich jetzt nicht unbedingt nur Zeitmessung verstanden, sondern eine ganz allgemeine Codeanalyse, wodurch auch Assambleranalysen dazugehören.

    Nexus schrieb:

    Abgesehen davon deutet mein "generell" darauf hin, dass es nicht nur um den speziellen Fall hier geht.

    Naja, meine Antwort war auch generell gemeint. Bei jedem Problem wird man sich zuerst keine grösseren Gedanken machen und danach schauen, was schneller ist.

    Ich persönlich würde zuerst einfach auf RVO setzen und danach schauen, ob es Probleme macht. Grund dafür ist, dass die RVO Lösung die einfachste und sauberste ist. Man kann sie einfach warten und setzt noch keinerlei Tricks ein. Tricks sollte man erst einsetzen, wenn man anfängt zu optimieren. Zumindest ist das eben meine Meinung 🙂

    Grüssli



  • Dravere schrieb:

    Bei jedem Problem wird man sich zuerst keine grösseren Gedanken machen und danach schauen, was schneller ist.

    Das kann man so nicht stehen lassen. Es schadet nie, sich zum Laufzeitverhalten im Voraus Überlegungen anzustellen, gerade wenn es sich nicht um Mikrooptimierungen handelt. Aber wir müssen die Premature-Optimization-Diskussion nicht zum x-ten Mal führen, wir sind uns grösstenteils eh einig 🙂

    Dravere schrieb:

    Ich persönlich würde zuerst einfach auf RVO setzen und danach schauen, ob es Probleme macht. Grund dafür ist, dass die RVO Lösung die einfachste und sauberste ist. Man kann sie einfach warten und setzt noch keinerlei Tricks ein.

    Ah, du meinst im Bezug auf const_cast . Ja, das habe ich auch vor. Dennoch hätte mich interessiert, ob hier ein const_cast überhaupt erlaubt wäre. Der Standard drückt sich nämlich nicht ganz klar aus (denn das temporäre Objekt ist ja nicht konstant):

    §7.1.5.1/4 The cv-qualifiers schrieb:

    Except that any class member declared mutable can be modified, any attempt to modify a const object during its lifetime results in undefined behavior.


  • Administrator

    Nexus schrieb:

    Dennoch hätte mich interessiert, ob hier ein const_cast überhaupt erlaubt wäre. Der Standard drückt sich nämlich nicht ganz klar aus (denn das temporäre Objekt ist ja nicht konstant):

    §7.1.5.1/4 The cv-qualifiers schrieb:

    Except that any class member declared mutable can be modified, any attempt to modify a const object during its lifetime results in undefined behavior.

    Ich würde in einem anderen Abschnitt suchen: 12.2 Temporary objects, Abschnitt 5
    Da geht es darum, dass die Lebensdauer von temporären Objekten verlängert wird, wenn sie an eine Referenz auf ein konstantes Objekt gebunden werden. Sicher bin ich mir nicht, aber womöglich könnte es funktionieren, da die Lebensdauer des temporären Objektes bis zum Ende des Konstruktors von MyClass verlängert wird. Den ganzen Text in diesem Abschnitt will ich jetzt hier nicht reinkopieren. Kann sich jeder selber anschauen, welcher einen C++ Standard zuhause rumliegen hat. 🙂

    Grüssli



  • Es geht ja mehr um die const -Qualifizierung als die Lebensdauer. Dass ein Const-Referenz-Parameter temporäre Objekte am Leben hält, ist mir bewusst.

    Von mir aus gesehen müsste der const_cast prinzipiell funktionieren (was nicht heisst, dass ich ihn hier einsetzen werde).



  • Wenn du das Convertible wirklich nur in dem einen Zusammenhang verwendest, was spräche dann dagegen:

    class Convertible
    {
      mutable CopyExpensive member;
    };
    
    //[...]
    
    MyClass::MyClass(Convertible const& c)
    {
      member.swap(c.member); //kein böser const_cast nötig ;)
      //...
    }
    

  • Administrator

    Nexus schrieb:

    Es geht ja mehr um die const -Qualifizierung als die Lebensdauer. Dass ein Const-Referenz-Parameter temporäre Objekte am Leben hält, ist mir bewusst.

    Ich würde schon sagen, dass es um die Lebensdauer geht. Schlussendlich geht es nämlich darum, auf welches Objekt die Referenz verweist und ob dieses Objekt konstant ist oder nicht. Wenn du daher ein nicht konstantes Objekt zurückgibst und die Lebensdauer dieses temporären Objektes verlängerst bis nach dem Ausführen des Konstruktors, dann verweist die Referenz auf ein tatsächlich nicht konstantes Objekt. Das war zumindest meine Überlegung, ob die stimmt ist eine andere Frage 🤡

    Grüssli



  • Okay. Danke auch für deinen Vorschlag, pumuckl. Dass ich da nicht drauf gekommen bin... 😉


Anmelden zum Antworten