2016-01-22 14 views
9

I mich fragen, welche Teile des Standard, die angeben, in dem folgende Codesegment:C++: Umsetzungen von L-Wert-Referenzen und rvalue verweisen

#include <memory> 

class A { }; 

class B : public A { }; 

int main() 
{ 
    std::unique_ptr<B> bptr = std::make_unique<B>(); // (a) 
    std::unique_ptr<A> aptr = std::move(bptr);  // (b) 
    std::unique_ptr<A> &aptr_r = bptr;    // (c) 
    std::unique_ptr<A> &&aptr_rr = std::move(bptr); // (d) 
    return 0; 
} 

(d) kompiliert und (c) dies nicht tut. Bitte fügen Sie die relevanten Teile des Standards in Ihre Antwort ein oder beziehen Sie sich entsprechend darauf. Nur als Referenz, Ubuntu Klirren Version 3.6.2-1 (Tags/RELEASE_362/final) (basierend auf LLVM 3.6.2) gibt mir

error: non-const lvalue reference to type 'unique_ptr<A>' cannot 
     bind to a value of unrelated type 'unique_ptr<B>' 
     std::unique_ptr<A> &aptr_r = bptr; 
         ^  ~~~~ 

und gcc (Ubuntu 5.2.1-22ubuntu2) 5.2 0,1 20151010 gibt mir

error: invalid initialization of reference of type ‘std::unique_ptr<A>&’ 
     from expression of type ‘std::unique_ptr<B>’ 
     std::unique_ptr<A> &aptr_r = bptr; 
            ^

Edit:

Auf meine Frage mehr klar, lassen Sie mich zu machen hinzufügen

class C { }; 

std::unique_ptr<C> cptr = std::make_unique<C>(); // (e) 
std::unique_ptr<A> &&aptr_rr2 = std::move(cptr); // (f) 

Was verhindert (f) das Kompilieren, wenn (d)? Offensichtlich A und C sind unabhängig, aber wo ist, dass erfasst wird, wenn der std::unique_ptr Konstruktor verwendet, um die temporäre Konstrukt für beide (d) und (f) ist

template<class U, class E> 
unique_ptr(unique_ptr<U, E> &&u); 
+2

(http://coliru.stacked-crooked.com/a/7e47cee922d95250) – chris

+4

' (c) ' kompiliert nicht, da 'aptr_r' und' bptr' unterschiedliche Typen sind und somit 'aptr_' keine Referenz des' bptr' sein kann. Es ist so: 'int x = 0; float & y = x; '. Aber '(d)' kompiliert, weil ein temporäres Objekt des Zieltyps aus dem Ausdruck 'std :: move (bptr)' .. erzeugt wird und das temporäre Objekt an die rvalue-Referenz bindet. Beachten Sie, dass 'bptr' nach dem Erstellen dieser rvalue-Referenz null wird, da sie verschoben wurde. – Nawaz

Antwort

4

Der wesentliche Unterschied zwischen den Fällen, in der Tatsache liegt, dass rvalue Referenzen können indirekt (über ein temporäres) binden, während Nicht-0-Referenzen Referenzen nicht können. Sowohl in (c) als auch (d) ist der Initialisierer dem in [dcl.init.ref]/(5.1) angegebenen Typ nicht ähnlich oder umwandelbar, daher muss [dcl.init.ref]/(5.2) gelten - sofort ausschließend (c):

Andernfalls wird die Referenz eine L-Wert Bezugnahme auf einen nichtflüchtigen const Typen sein (dh CV1 soll const sein), oder die Referenz wird ein R-Wert Bezug.

Beachten Sie auch, dass unique_ptr<A> und unique_ptr<B> verschieden sind, nicht verwandten Arten, unabhängig davon, wie A und B sind verwandt.

Sie können diese Regel beobachten with scalars, too: [. Nicht wirklich `unique_ptr` spezifisch]

int&& i = 0.f; // Ok 
int& i = 0.f; // Not ok