2016-01-22 14 views
9

Ciekawe, których części standardu określa, że ​​w kolejnym segmencie kodu:C++ konwersji lwartości odniesienia i rvalue odwołuje

#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) kompiluje i (c) nie ma. Proszę podać odpowiednie części standardu w swojej odpowiedzi lub odnieść się do nich odpowiednio. Tylko w celach informacyjnych, Ubuntu wersja dzyń 3.6.2-1 (tags/RELEASE_362/final) (oparty na LLVM 3.6.2) daje mi

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; 
         ^  ~~~~ 

i gcc (5.2.1-22ubuntu2 Ubuntu) 5,2 0,1 20151010 daje mi

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:

aby moje pytanie bardziej jasne, dodam

class C { }; 

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

Co to jest utrzymywanie (f) z kompilacji, gdy (d) ma miejsce? Oczywiście A i C są niezależne, ale gdzie jest wykrywany, gdy konstruktor std::unique_ptr wykorzystane do skonstruowania tymczasowy dla obu (d) i (f) jest

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

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

+4

' (c) ' nie kompiluje się, ponieważ 'aptr_r' i' bptr' są różnych typów, a zatem 'aptr_' nie może być odniesieniem do' bptr'. Jest tak: 'int x = 0; float i y = x; '. Ale '(d)' kompiluje, ponieważ tymczasowy obiekt typu docelowego, jest tworzony z wyrażenia 'std :: move (bptr)' .. i tymczasowy obiekt wiąże się z referencją rvalue. Zwróć uwagę, że po utworzeniu tego odwołania rvalue, 'bptr' staje się puste, ponieważ zostało przeniesione. – Nawaz

Odpowiedz

4

Kluczową różnicą między przypadkach polega na tym, że rvalue odniesienia mogą wiązać się pośrednio (przez tymczasowy), podczas gdy odniesienia o wartości l. nie mogą. Zarówno w (c), jak i (d) inicjator nie jest podobny ani nie może być wymieniony na typ określony jako określony w [dcl.init.ref]/(5.1), dlatego [dcl.init.ref]/(5.2) musi obowiązywać - natychmiast wyklucza (c):

przeciwnym razie referencyjna wynosi lwartością odniesienie do nieulotnej const typu (tzn CV1 będzie const) lub odniesienie powinno być odniesienie RValue.

Należy również zauważyć, że unique_ptr<A> i unique_ptr<B> są odrębne, niepowiązane typy, niezależnie od tego, jak A i B są powiązane.

można obserwować tę zasadę with scalars, too: [. Niezupełnie `unique_ptr` specyficzne]

int&& i = 0.f; // Ok 
int& i = 0.f; // Not ok 
Powiązane problemy