2010-02-19 9 views
21

Czy ktoś mógłby wyjaśnić szczegóły w zakresie wartości r, sł., POD i nie-POD, dlatego pierwsze wyrażenie zaznaczone poniżej to , a nie ok, podczas gdy drugie wyrażenie zaznaczone poniżej to ok? W moim rozumieniu zarówno int() jak i A() powinny być wartościami r, nie?POD, wartości inne niż POD, wartości r i l.


struct A {}; 

int main() 
{ 
    int i; 
    A a; 

    int() = i; //Not OK (error). 
    A() = a; //OK. 

    return 0; 
} 

Odpowiedz

17

Rvalues ​​są tym, co można uzyskać z wyrażeń (użytecznego uproszczenia pobranej od standardu C, ale nie sformułowane w języku C++ standardese). Wartości L są "wartościami lokalizatora". Wartości L można stosować jako wartości r. Odnośniki są zawsze wartościami l, nawet jeśli const.

Najważniejszą różnicę, o której musisz wiedzieć, można skondensować do jednego elementu: nie można przyjąć adresu wartości rwart (ponownie, nie jest to standardowe, ale użyteczne uogólnienie reguł). Lub, mówiąc inaczej, nie możesz ustalić dokładnej lokalizacji dla wartości rvalue —, jeśli mógłbyś, to masz wartość lvalue. (Możesz jednak związać stałą o wartości &, aby "naprawić ją na miejscu", a 0x bardzo drastycznie zmieniła reguły.)

Zdefiniowane przez użytkownika typy (UDT) są jednak nieco wyjątkowe: można przekonwertować dowolny rvalue do lwartością, jeśli klasa interfejs pozwala go:

struct Special { 
    Special& get_lvalue() { return *this; } 
}; 
void f() { 
    // remember "Special()" is an rvalue 
    Special* p = &Special().get_lvalue(); // even though you can't dereference the 
    // pointer (because the object is destroyed), you still just took the address 
    // of a temporary 

    // note that the get_lvalue() method doesn't need to operate on a const 
    // object (though that would be fine too, if the return type matched) 
} 

Coś podobnego dzieje się za A() = a, z wyjątkiem przez operatora przypisania kompilatora dostarczone, aby włączyć rvalue A() do *this. Zacytować standard, 12,8/10:

Jeżeli definicja klasy nie jawnie zadeklarować operatora przypisania kopia, jeden jest zadeklarowana niejawnie. Niejawnie zadeklarowanej operator przypisania kopia dla klasy X będzie mieć formę

X& X::operator=(const X&) 

A potem to idzie z większą kwalifikacji i widowisko, ale to jest istotne bit tutaj. Ponieważ jest to funkcja członkowska, można ją wywoływać na wartościach r, podobnie jak Special :: get_lvalue może być, tak jakbyś napisał A().operator=(a) zamiast A() = a.

Podczas odkrywania jawnie zabronione jest int() = 1, ponieważ ints nie mają operatora = zaimplementowanego w ten sam sposób. Jednak ta niewielka rozbieżność między typami nie ma znaczenia w praktyce (przynajmniej nie, że znalazłem).


POD oznacza zwykłe stare dane i jest zbiorem wymagań, które określają użycie memcpy, co odpowiada kopiowaniu. Non-POD jest dowolnym typem, którego nie można użyć do kopiowania memcpy (naturalne przeciwieństwo POD, nic nie jest tu ukryte), który zwykle jest typem, który napiszesz w C++. Bycie POD lub non-POD nie zmienia żadnego z powyższych i jest naprawdę oddzielnym problemem.

+0

Specyficzny dla C, ale nadal przydatny dla programistów C++ do zrozumienia: http://stackoverflow.com/questions/2038414/lvalue-and-rvalue/2038427#2038427. (Jest to jedna z dziedzin, w których oba języki zasadniczo się dzielą, mimo że C++ jest nieco bardziej skomplikowana z odniesieniami i faktycznie używa terminu "rvalue", którego C już nie ma). –

+0

"_Or, mówiąc inaczej, nie możesz Napraw dokładną lokalizację dla wartości r "zgodnie ze standardem językowym, wartość rdzenia podstawowego nie jest nawet obiektem i nie ma adresu. – curiousguy

1

Z Does C++ do value initialization of a POD typedef?, które przytacza standard:

Wyrażenie (T), gdzie T jest prosty typu specyfikator (7.1.5.2) dla bez matrycy pełnego obiektu Typ lub (ewentualnie CV zastrzeżeniami) nieważności typu tworzy rValue określonego typu, który jest inicjowany wartością

Dlatego int() jest wartością runtue i nie można jej przypisać, jak widzieliśmy w pierwszym przypadku.

A() nie będzie simlle-type-specifyer a więc() daje lwartością

+2

Link ten prowadzi cyklicznie do tej strony. W §5.2.3 wyraźnie określono, że T() jest rwartą, niezależnie od typu. – Potatoswatter

+0

Naprawiono link - błąd w FireFox (nie zmieniał paska adresu przy przełączaniu kart) – DVK

+2

Nawet przy niewłaściwym łączu odpowiedź byłaby poprawna, ponieważ odsyłacz wskazywałby stronę z linkiem do strony z linkiem do strona ... z cytatem. Szkoda, że ​​to nie była rekursja ogona. :-). –

2

W moim rozumieniu zarówno int() jak i A() powinny być wartościami r, nie?

poprawny, epxression T() zawsze rvalue dla skalarnych i użytkownika rodzaju T. Tak długo, jak nie ma to miejsca, wyrażenie T() jest modyfikowalną wartością r_u_tu , aby być bardziej precyzyjnym.

Przyporządkowanie z użyciem typów skalarnych wymaga zmodyfikowanej wartości o wartości po lewej stronie operatora przypisania. Ponieważ int() nie jest lwartością, nie można przypisać do int().

Dla typów zdefiniowanych przez użytkownika przypisanie jest specjalną funkcją składową, a funkcje składowe można również wywoływać na rwartościach (patrz §3.10 sekcja 10). Właśnie dlatego A().operator=(a) jest dobrze uformowany.

+0

'int()' jest _modowalną wartością r? – curiousguy

+0

@ciałoguy: Tak. [Nie ma stałych skalarnych wartości r] (http://stackoverflow.com/questions/2169932/). – fredoverflow

+0

Jak to zmienić? – curiousguy

Powiązane problemy