return value optimierung (RVO)-Frage



  • Hallo,
    meiner Meinung nach müsste der Kopierkonstruktor bei temporären Größen wegoptimiert werden. Was ich nicht verstehe ist, warum h3() und h4() sich bezgl. RVO unterschiedlich verhalten:

    #include<iostream>
    #include<utility>
    
    class A {
    public:
      explicit A(int w) : wert(w) {
        std::cout << "A(int) aufgerufen\n";    
      }
      A(const A& a)  : wert(a.get()) {
        std::cout << "A(const A&) aufgerufen\n"; 
      }
      A(A&& a)  : wert(std::move(a.get())) {
        std::cout << "A(A&&) aufgerufen\n"; 
      }
      A& operator=(const A&) = default;
      A& operator=(A&&) = default;
      int get() const { return wert; }
      A& set(int w)  { wert = w; return *this; }
    private:
      int wert;
    };
    
    inline A h3() {              // temporary 1, ok: RVO
      return A(17);
    }  
    
    inline A h4(const A& a) {   // temporary 2: Wieso kein RVO?
      return (A(a)).set(99); 
    }  
    
    inline A h5(const A& a) {   // temporary: ok, move c'tor
      return std::move((A(a)).set(42)); 
    }  
    
    int main() {
      A lvalue(5);
      A a1 = h3();
      std::cout << "h3()  wert = " << a1.get() << "\n\n";  
      int result = h4(lvalue).get();
      std::cout << "h4(lvalue) wert = " << result << "\n\n";
      result = h5(lvalue).get();
      std::cout << "h5(lvalue) wert = " << result << "\n\n";
    }
    

    Warum wird bei h4() der Kopierkonstruktor zweimal aufgerufen statt nur einmal wie bei h5()?
    Bei zurückgegebenen Funktionsparametern erfolgt kein RVO, aber bei h4() wird der Parameter a nicht zurückgegeben, nur verwendet.


  • Mod

    Hier noch einmal die relevante Standardpassage:

    [class.copy]/31 schrieb:

    This elision of copy/move operations, called copy elision, is permitted in the following circumstances (which
    may be combined to eliminate multiple copies):

    • in a return statement in a function with a class return type, when the expression is the name of a
      non-volatile automatic object (other than a function or catch-clause parameter) with the same cv-
      unqualified type as the function return type, the copy/move operation can be omitted by constructing
      the automatic object directly into the function’s return value
    • in a throw-expression […]
    • when a temporary class object that has not been bound to a reference (12.2) would be copied/moved
      to a class object with the same cv-unqualified type, the copy/move operation can be omitted by
      constructing the temporary object directly into the target of the omitted copy/move
    • when the exception-declaration […]

    In h4 gibst du ein lvalue zurück, eine Referenz. Eine Referenz ist aber keine Temporary. Und ob sie auf ein Objekt verweist das man als Temporary bezeichnen könnte ist irrelevant.

    Gemoved wird auch nicht, gerade weil copy elision nicht applikabel ist. Um das zu verhindern kannst du ein C++11 feature anwenden:

    A&  set(int w) &  { wert = w; return *this; } 
      A&& set(int w) && { wert = w; return std::move(*this); }
    


  • ja, danke. set() gibt eine Referenz A& zurück, kein Objekt. Damit ist die Frage geklärt.


Anmelden zum Antworten