nichtkonstanter rückgabewert direkt verwenden


  • Administrator

    Schnupfbear schrieb:

    misst die Leerzeichen wurden verschluckt...

    Verwende Code-Tags 😉

    Schnupfbear schrieb:

    ps gibt es kein Edit-Button?

    Wenn du registriert bist schon. Man kann die einzelnen Unregistrierten nicht unterscheiden, daher auch keine Edit-Möglichkeiten anbieten.

    Und was ist deine Frage? 🙂
    Deine Wrapper-Klasse ist nicht kopierbar, falls dies das Problem ist, weil du darin Referenzen als Member verwendest.

    Grüssli



  • Dravere schrieb:

    Schnupfbear schrieb:

    misst die Leerzeichen wurden verschluckt...

    Verwende Code-Tags 😉

    Schnupfbear schrieb:

    ps gibt es kein Edit-Button?

    Wenn du registriert bist schon. Man kann die einzelnen Unregistrierten nicht unterscheiden, daher auch keine Edit-Möglichkeiten anbieten.

    Und was ist deine Frage? 🙂
    Deine Wrapper-Klasse ist nicht kopierbar, falls dies das Problem ist, weil du darin Referenzen als Member verwendest.

    Grüssli

    Und gibt es kein Workaround damit das Wrapperobjekt beschreibbar zurückgegeben wird?


  • Administrator

    Speichere Zeiger statt Referenzen. Allerdings wird das in einer Katastrophe enden, weil du dann Zeiger auf temporäre Objekte speicherst und wohl später darauf zugreifen möchtest. Wenn du dir zum Beispiel mal die folgende Auswertung ansiehst:

    1. B+C gibt ein temporäres Objekt vom Typ Wrapper<TestClass, TestClass> zurück. Es speichert intern Zeiger auf B und C . Noch ist alles in Ordnung.
    2. A+ (1.) gibt ein Wrapper<TestClass, Wrapper<TestClass, TestClass> > zurück. LHS zeigt auf A , was kein Problem ist. RHS zeigt dann allerdings auf das temporäre Objekt, welches bei 1. erzeugt und grundsätzlich auch gleich wieder zerstört wurde. Jeglicher spätere Zugriff darauf resultiert in undefiniertem Verhalten.

    Dir bleibt somit nichts anderes übrig, als dass du Kopien machst oder einen C++0x Compiler mit Move-Konstruktoren verwendest.

    Grüssli



  • Der aktuelle operator+ dürfte doch auch gar nicht kompilieren: Du nimmst non-const-Referenzen als Paramater entgegen, rufst die Funktion dann aber mit temporären Objekten auf. -> Error. Mit const-Referenzen würde das mit temporären Objekten wieder gehen.



  • l'abra d'or schrieb:

    Der aktuelle operator+ dürfte doch auch gar nicht kompilieren: Du nimmst non-const-Referenzen als Paramater entgegen, rufst die Funktion dann aber mit temporären Objekten auf. -> Error. Mit const-Referenzen würde das mit temporären Objekten wieder gehen.

    Richtig...deswegen frage ich ja um Rat...
    Ich brauche nämlich nicht Konstante Rückgabewerte damit ich später die Daten noch verändern kann;
    Gebe ich direkt eine Referenz, dann endet es direkt, wie Dravere es beschrieben hat, in einer Katastrophe.

    Das mit dem Move-konstruktor klingt viel versprechend. Habe mich da auch schon etwas eingelesen aber wie genau ich das,in diesem Beispiel mit den RValues machen soll, weis ich noch nicht...



  • Was spricht dagegen, einfach Werte zu verwenden? Keine Zeiger, keine Referenzen einfach Werte. Wenn sich im Nachhinein herausstellt, dass dies für einige Type zu inperformant ist (nach dem man gemessen hat, dass genau dass, das Problem ist), kann man den Type auf einfaches Kopieren hin optimieren.

    mfg Torsten



  • Torsten Robitzki schrieb:

    Was spricht dagegen, einfach Werte zu verwenden? Keine Zeiger, keine Referenzen einfach Werte. Wenn sich im Nachhinein herausstellt, dass dies für einige Type zu inperformant ist (nach dem man gemessen hat, dass genau dass, das Problem ist), kann man den Type auf einfaches Kopieren hin optimieren.
    mfg Torsten

    "Testtype" ist der "Wert" und er ist ziemlich groß; kopieren kommt da nicht in Frage.
    "Wrapper" dient letzendlich dazu, die "Werte" zu Ordnen und für "Templatemagie" aufzubereiten.



  • Schnupfbear schrieb:

    "Testtype" ist der "Wert" und er ist ziemlich groß; kopieren kommt da nicht in Frage.

    Dann optimiere den Typen doch für Kopieren. "copy on write" (COW) wäre da z.B. ein Stichwort. Du trennst den Typen in ein Body und ein Handel, wobei der Body mit einem Referenzzähler versehen ist. Bei schreibenden Zugriffen auf den Body über das Handle, guckst Du, ob der Body mehr als einmal referenziert wird. Ist dem so, machst Du Dir Deine eigene Kopie des Bodies. Der copy c'tor des handles sieht dann so aus, dass er den Zeiger auf den Body kopiert und dort die Anzahl der Referenzen um eins erhöht.

    mfg Torsten



  • Wie wärs damit?

    class IWrapper{};
    template<class lhs , class rhs>
    class Wrapper : IWrapper
    {
      lhs & LHS;
      rhs & RHS;
    public:
    
      Wrapper(lhs & LHS, rhs & RHS) : LHS(LHS), RHS(RHS) {}
    
    /* IMPL... */
    };
    
    template<class lhs , class rhs, bool L = std::is_base_of<IWrapper,lhs>::value,  bool R = std::is_base_of<IWrapper,lhs>::value >
    inline typename
    std::enable_if< !(L||R), Wrapper<lhs,rhs> >
    ::type&& operator+(lhs & LHS, rhs & RHS) {
      Wrapper<lhs,rhs> Result(LHS,RHS);
      /*.....*/
      return std::move(Result);
    }
    
    template<class lhs , class rhs, bool L = std::is_base_of<IWrapper,lhs>::value,  bool R = std::is_base_of<IWrapper,lhs>::value >
    inline typename
    std::enable_if< (!L&&R), Wrapper<lhs,rhs> >
    ::type&& operator+(lhs & LHS, rhs  RHS) {
      Wrapper<lhs,rhs> Result(LHS,RHS);
      /*.....*/
      return std::move(Result);
    }
    
    template<class lhs , class rhs, bool L = std::is_base_of<IWrapper,lhs>::value,  bool R = std::is_base_of<IWrapper,lhs>::value >
    inline typename
    std::enable_if< (L&&!R), Wrapper<lhs,rhs> >
    ::type&& operator+(lhs LHS, rhs & RHS) {
      Wrapper<lhs,rhs> Result(LHS,RHS);
      /*.....*/
      return std::move(Result);
    }
    
    template<class lhs , class rhs, bool L = std::is_base_of<IWrapper,lhs>::value,  bool R = std::is_base_of<IWrapper,lhs>::value >
    inline typename
    std::enable_if< (L&&R), Wrapper<lhs,rhs> >
    ::type&& operator+(lhs  LHS, rhs  RHS) {
      Wrapper<lhs,rhs> Result(LHS,RHS);
      /*.....*/
      return std::move(Result);
    }
    
    class Testclass {};
    
    int main()
    {
      Testclass A;
      Testclass B;
      Testclass C;
    
      A+B+C;
    }
    

    Hat jemand ne elegantere Möglichkeit gefunden? - was wenns mehr als 2 Argumente sind?
    Das hat leider nicht funktioniert, der Compiler war stets nicht in der lage die Funktion zu finden(auser man gibt die Parameter explizit an):

    template<bool Cond, class A, class B>
    struct IF
    {
      typedef A type;
    };
    
    template<bool Cond, class A, class B>
    struct IF<false,A,B>
    {
      typedef B type;
    };
    
    template<class lhs , class rhs, bool L = std::is_base_of<IWrapper,lhs>::value,  bool R = std::is_base_of<IWrapper,lhs>::value >
    Wrapper<lhs,rhs> operator+( typename IF<L,lhs&,lhs>::type LHS , typename IF<R,rhs&,rhs>::type RHS )
    

    MFG
    Speed



  • @Speed : funktioniert leider nur wenn Compiler-Optimierungen aktiviert sind(G++-4.5)

    Torsten Robitzki schrieb:

    Dann optimiere den Typen doch für Kopieren. "copy on write" (COW) wäre da z.B. ein Stichwort. Du trennst den Typen in ein Body und ein Handel, wobei der Body mit einem Referenzzähler versehen ist. Bei schreibenden Zugriffen auf den Body über das Handle, guckst Du, ob der Body mehr als einmal referenziert wird. Ist dem so, machst Du Dir Deine eigene Kopie des Bodies. Der copy c'tor des handles sieht dann so aus, dass er den Zeiger auf den Body kopiert und dort die Anzahl der Referenzen um eins erhöht.
    mfg Torsten

    Sehe es irgendwie nicht ein wieso ich ein Kopieroverhead in kauf nehmen soll, obwohl der Compiler ja tun könnte(könnte er?:-), was ich möchte.

    Der Code Funktioniert ja, wenn man ihn in Zwischenschritte aufspaltet und die Ergebnisse einer Variable zuweist(ist uns sogar lieber, als viel rumzukopieren):

    auto X = A+B;
    auto Y = X+C;
    auto Z = Y+D;
    //usw
    

    Dann sollte man vielleicht wissen, dass eigentlich "Wrapper" dazu eingeführt worden ist, um ein paar Features durch "template-Magie" zu ermöglichen - ohne Kopieren zu müssen. Jetzt wollten wir zusätzliche Features, mit Schreiboperationen, einführen, da entschloss ich im "operator+" das "const&" in "&" umzuschreiben... naja und dann bin ich hierher gelandet ;P

    LG


Anmelden zum Antworten