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.
-
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
returnstatement 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
h4gibst 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); }
- in a
-
ja, danke. set() gibt eine Referenz
A&zurück, kein Objekt. Damit ist die Frage geklärt.