2016-03-21 8 views
1

Gibt es einen Unterschied im Verhalten, wenn der Rückgabetyp explizit rvalue vs no ref deklariert ist? Nach dem folgenden Beispiel scheint es keinen Unterschied zu geben.Unterschied zwischen && und keine ref als Rückgabetyp

#include <iostream> 
#include <vector> 
using namespace std; 

struct A { 
    A(int x) : x_(x) {} 

    A(A&&) = default; // VC12 hasn't implemented default move 
    A(const A&) = delete; 
    A& operator=(A&&) = default; 
    A& operator=(const A&) = delete; 

    vector<int> x_; 
}; 

struct B{ 
    B(int x) : a_(x) {} 
    A&& foo1() { return move(a_); } // explicitly declared as rvalue 
    A foo2() { return move(a_); } // no ref 
    A a_; 
}; 

int main() { 
    B b1(7); 
    A a1 = b1.foo1(); 
    B b2(7); 
    A a2 = b2.foo2();  
    cout << a1.x_.size() << ' ' << a2.x_.size() << endl; 
    cout << b1.a_.x_.size() << ' ' << b2.a_.x_.size() << endl; 
    return 0; 
} 

Dieses Beispiel wird von Ideone des C++ 14-Compiler kompiliert worden (nicht sicher über die genaue Version, vermute ich, es Gnu 5.1 ist) und VC12 (Visual Studio 2013). Der einzige kleine Unterschied ist, dass VC12 eine explizite Move-Implementierung erfordert.

Edit: A related SO post sagte, dass die beiden Funktionen am Ende die gleiche Sache tun. "In vielen Fällen erlaubt es dem Compiler jedoch, die Elision zu kopieren und die Aufrufe des Move-Konstruktors des zurückgegebenen Typs zu verhindern, wie es in Absatz 12.8/31 des C++ 11-Standards erlaubt ist". "Elision kopieren ermöglicht dem Compiler, den Rückgabewert der Funktion direkt im Objekt zu erzeugen."

Frage 1: Kopieren Elision sollte immer noch passieren, wenn Move explizit aufgerufen wird, oder?

Frage 2: Wenn Bewegung explizit auf einem L-Wert genannt wird (so ein genannt erforderlich), ein & & und A bedeutet das gleiche Verhalten. Wenn move nicht explizit aufgerufen wird, dh, der Compiler führt die Eliminierung durch, sollte A der einzige Rückgabetyp sein. Kombinieren Sie die beiden oben genannten Szenario, kann ich daraus schließen, dass Rückgabetyp A & & nicht sinnvoll ist und nur Verwirrung verursacht?

+0

* Gibt es einen Unterschied im Verhalten, wenn der Rückgabetyp ausdrücklich als rvalue deklariert ist? * - im Gegensatz zu ** what **? – SergeyA

+0

@SergeyA keine Referenz, siehe B :: foo1 und B :: foo2. –

+0

Gewöhnen Sie sich nicht an 'return move (something)'. Es ist nutzlos und wird implizit angewendet (siehe: Elision kopieren, Rückgabewertoptimierung, Rückgabewertkonstruktion) –

Antwort

2

Mit

A&& foo1() { return move(a_); } 
A foo2() { return move(a_); } 
  • foo1 liefert einen (rvalue) Referenz.
  • foo2 Konstruieren Sie ein Objekt A mit dem Move-Konstruktor.
+0

Erwarten Sie, dass sich die beiden anders verhalten? In diesem Beispiel verhalten sie sich gleich. –

+1

@CandyChiu Er erklärte bereits, dass die beiden sich anders verhalten :) Im zweiten Fall gibt es einen Bewegungsaufbau, und nicht im ersten Fall. – Praetorian

+0

@Praetorian ABER es gibt keinen Unterschied nach dem Beispiel. Ich habe sogar gedruckt, wie oft der Move-Konstruktor aufgerufen wurde. –