Tymczasowe nie mogą być powiązane z niestałymi odwołaniami. int (12) jest w tym przypadku tymczasowym.
Prasoon Saurav
@PrasoonSaurav Co masz na myśli mówiąc o tymczasowej 12? Brak koncepcji tutaj (z mojej strony :))
Aquarius_Girl
2
Zauważ, że nie ma ścisłego technicznego powodu tego ograniczenia. Równie łatwo byłoby zaimplementować zezwolenie na zmienne odniesienia do tymczasowych. Zakazanie tego jest decyzją projektową C ++, ponieważ taka konstrukcja byłaby kiepskim projektem o znacznie większym ryzyku nieumyślnego nadużycia niż autentyczna użyteczność. (Tylko raz znalazłem wymyśloną potrzebę czegoś takiego.)
Kerrek SB
@KerrekSB prawdopodobnie najczęstszą potrzebą powiązania odniesienia do obiektu rvalue jest(ostringstream() << "x=" << x).str()
curiousguy.
@curiousguy: Tak, to jest treść linku, który zamieściłem.
Kerrek SB
Odpowiedzi:
132
C ++ 03 3.10 / 1 mówi: „Każde wyrażenie jest albo lwartością, albo rwartością”. Należy pamiętać, że wartość kontra wartość jest właściwością wyrażeń, a nie przedmiotów.
Lvalues nazywają obiekty, które pozostają poza jednym wyrażeniem. Na przykład obj, *ptr, ptr[index], i ++xsą lwartościami.
Wartości R to wartości tymczasowe, które wyparowują na końcu pełnego wyrażenia, w którym żyją („w średniku”). Na przykład 1729, x + y, std::string("meow"), i x++są rvalues.
Operator address-of wymaga, aby jego „operand był l-wartością”. gdybyśmy mogli wziąć adres jednego wyrażenia, wyrażenie jest lwartością, w przeciwnym razie jest to rwartość.
„ gdybyśmy mogli wziąć adres jednego wyrażenia, wyrażenie jest lwartością, w przeciwnym razie jest to wartość r. ” gdyby tylko C ++ był taki prosty! (ale ten niuans nie jest tutaj zbyt istotny) „Wartości R są tymczasowe” co tymczasowe? przedmioty?
curiousguy
2
Wartości @curiousguyR to wartości tymczasowe, które znikają pod koniec pełnego wyrażenia, w którym żyją. Aby po prostu odpowiedzieć, dlaczego wyrażenie int & = 12;jest nieprawidłowe, standard mówi, że literał łańcuchowy to lwartość, a inne literały to rwartości.
BruceAdi
@curiousguy: Tak. Wartości r są obiektami tymczasowymi , ale nie wszystkie wartości r są obiektami tymczasowymi; niektóre nie są nawet przedmiotami.
Nawaz
„ Na przykład 1729 x + y, std :: łańcucha (” meow „), a x ++ są rvalues. ”, Lecz std::string("meow")tworzy się obiekt typu std::stringi daje RValue że wyznacza tego celu, 1729nie ma działań ubocznych i plony wartości 1729 jako rwartość typu int.
curiousguy
1
@curiousguy: To stwierdzenie "Lvalues name objects that persist beyond a single expression."jest w 100% poprawne. Wręcz przeciwnie, twój przykład (const int &)1jest niepoprawny, ponieważ NIE jest „nazwanym” obiektem.
Nawaz
53
int &z = 12;
Po prawej stronie tymczasowy obiekt typu intjest tworzony z integralnego literału 12, ale tymczasowy nie może być powiązany z odwołaniem innym niż const. Stąd błąd. To jest to samo, co:
int &z = int(12); //still same error
Dlaczego tworzy się tymczasowy? Ponieważ odniesienie musi odnosić się do obiektu w pamięci, a aby obiekt istniał, musi zostać najpierw utworzony. Ponieważ obiekt nie ma nazwy, jest to obiekt tymczasowy . Nie ma imienia. Z tego wyjaśnienia stało się dość jasne, dlaczego drugi przypadek jest w porządku.
Obiekt tymczasowy można powiązać z odniesieniem do const, co oznacza, że możesz to zrobić:
constint &z = 12; //ok
C ++ 11 i Rvalue Reference:
Ze względu na kompletność chciałbym dodać, że C ++ 11 wprowadził rvalue-reference, które można powiązać z tymczasowym obiektem. Więc w C ++ 11 możesz napisać to:
int && z = 12; //C+11 only
Zauważ, że jest &&intead of &. Zauważ również, że constnie jest już potrzebne, mimo że obiekt, z którym się złączy, jest tymczasowym obiektem utworzonym z całki-literału 12.
Ponieważ C ++ 11 wprowadził odwołanie do wartości r , int&odtąd nazywane jest odniesieniem do wartości .
@curiousguy, bądź konsekwentny, powiedziałeś "Musisz zrozumieć, że to są reguły C ++. One istnieją i nie potrzebują żadnego uzasadnienia" (nie wspominając o pierwszym wydaniu). Jak mam zinterpretować twoje narzekanie, że nie dajesz tego, co według ciebie nie jest potrzebne?
Michael Krelin - haker
2
@ MichaelKrelin-hacker: Technicznie nie, nie możesz (nigdy) powiązać odniesienia z wartością (lub stałą czasową kompilacji), standard jest dość wyraźny co do tego, co się dzieje: w przeciwnym razie tworzony jest tymczasowy typ „cv1 T1” i zainicjowany z wyrażenia inicjatora przy użyciu reguł inicjowania kopii bez odniesienia (8.5). Odniesienie jest następnie powiązane z tymczasowym. Oznacza to, że składnia jest dozwolona, ale semantyka nie polega na wiązaniu odniesienia do stałej, ale raczej na wiązaniu go z tymczasowym, który jest domyślnie utworzony.
David Rodríguez - dribeas
1
@curiousguy: Reguły języka są częścią projektu i najczęściej istnieją uzasadnienia, dlaczego język został zaprojektowany w ten sposób. W tym szczególnym przypadku, tak jak w C, nie możesz wziąć adresu wartości (ona go nie ma) ani powiązać odwołania. Rozważmy teraz funkcję void f( vector<int> const & ), która jest idiomatyczna, aby przekazać wektor, który nie ma być modyfikowany. Problem polega teraz na tym f( vector<int>(5) ), że byłoby to niepoprawne, a użytkownik musiałby podać inne przeciążenie, void f( vector<int> v ) { f(v); }które jest trywialne.
David Rodríguez - dribeas
1
... teraz, ponieważ byłoby to bolesne dla użytkowników języka, projektanci zdecydowali, że kompilator wykona za Ciebie równoważną operację, w wywołaniu f( vector<int>(5) )kompilator utworzy tymczasową, a następnie wiąże odwołanie z tym tymczasowym i podobnie jeśli wystąpiła niejawna konwersja z 5bezpośrednio. Pozwala to kompilatorowi na wygenerowanie pojedynczego podpisu dla funkcji i umożliwia implementację funkcji przez jednego użytkownika. Od tego momentu podobne zachowanie jest definiowane dla pozostałych zastosowań stałych odniesień dla spójności.
David Rodríguez - dribeas
1
@ MichaelKrelin-hacker: odwołania to aliasy obiektów, a wartość nie jest obiektem. W zależności od kontekstu, odwołania mogą być po prostu aliasami, kompilator usuwa odniesienie i po prostu używa identyfikatora do oznaczenia cokolwiek oznaczał oryginalny obiekt ( T const & r = *ptr;każde późniejsze użycie rw funkcji może zostać zastąpione przez *ptri rnie musi istnieć w czasie wykonywania) lub może być zaimplementowane poprzez zachowanie adresu obiektu, do którego przypisuje aliasy (rozważ przechowywanie referencji jako członka obiektu) - który jest implementowany jako wskaźnik z autodreferencją.
David Rodríguez - dribeas
4
Wiązanie odniesienia inne niż stałe i stałe podlega innym regułom
Oto zasady języka C ++:
wyrażenie składające się z literału liczby ( 12) jest „wartością r”
nie jest dozwolone tworzenie referencji innych niż const z rvalue: int &ri = 12;jest źle sformułowana
dozwolone jest tworzenie odwołania do const z wartością r: w tym przypadku nienazwany obiekt jest tworzony przez kompilator; ten obiekt będzie istniał tak długo, jak długo istnieje odwołanie.
Musisz zrozumieć, że to są reguły C ++. Po prostu są.
Łatwo jest wymyślić inny język, na przykład C ++, z nieco innymi zasadami. W C ++ byłoby dozwolone utworzenie referencji niebędącej stałą z wartością r. Nie ma tu nic niespójnego ani niemożliwego.
Ale pozwoliłoby to na pewien ryzykowny kod, w którym programista mógłby nie uzyskać tego, co zamierzał, a projektanci C ++ słusznie postanowili uniknąć tego ryzyka.
Odniesienia to „ukryte wskaźniki” (niezerowe) do rzeczy, które mogą się zmieniać (lvalues). Nie możesz ich zdefiniować jako stałe. Powinna to być rzecz „zmienna”.
EDYTOWAĆ::
Myślę o
int &x = y;
jako prawie odpowiednik
int* __px = &y;
#define x (*__px)
gdzie __pxjest nową nazwą, a #define xdziała tylko wewnątrz bloku zawierającego deklarację xodniesienia.
(ostringstream() << "x=" << x).str()
Odpowiedzi:
C ++ 03 3.10 / 1 mówi: „Każde wyrażenie jest albo lwartością, albo rwartością”. Należy pamiętać, że wartość kontra wartość jest właściwością wyrażeń, a nie przedmiotów.
Lvalues nazywają obiekty, które pozostają poza jednym wyrażeniem. Na przykład
obj
,*ptr
,ptr[index]
, i++x
są lwartościami.Wartości R to wartości tymczasowe, które wyparowują na końcu pełnego wyrażenia, w którym żyją („w średniku”). Na przykład
1729
,x + y
,std::string("meow")
, ix++
są rvalues.Operator address-of wymaga, aby jego „operand był l-wartością”. gdybyśmy mogli wziąć adres jednego wyrażenia, wyrażenie jest lwartością, w przeciwnym razie jest to rwartość.
&obj; // valid &12; //invalid
źródło
int & = 12;
jest nieprawidłowe, standard mówi, że literał łańcuchowy to lwartość, a inne literały to rwartości.std::string("meow")
tworzy się obiekt typustd::string
i daje RValue że wyznacza tego celu,1729
nie ma działań ubocznych i plony wartości 1729 jako rwartość typuint
."Lvalues name objects that persist beyond a single expression."
jest w 100% poprawne. Wręcz przeciwnie, twój przykład(const int &)1
jest niepoprawny, ponieważ NIE jest „nazwanym” obiektem.int &z = 12;
Po prawej stronie tymczasowy obiekt typu
int
jest tworzony z integralnego literału12
, ale tymczasowy nie może być powiązany z odwołaniem innym niż const. Stąd błąd. To jest to samo, co:int &z = int(12); //still same error
Dlaczego tworzy się tymczasowy? Ponieważ odniesienie musi odnosić się do obiektu w pamięci, a aby obiekt istniał, musi zostać najpierw utworzony. Ponieważ obiekt nie ma nazwy, jest to obiekt tymczasowy . Nie ma imienia. Z tego wyjaśnienia stało się dość jasne, dlaczego drugi przypadek jest w porządku.
Obiekt tymczasowy można powiązać z odniesieniem do const, co oznacza, że możesz to zrobić:
const int &z = 12; //ok
C ++ 11 i Rvalue Reference:
Ze względu na kompletność chciałbym dodać, że C ++ 11 wprowadził rvalue-reference, które można powiązać z tymczasowym obiektem. Więc w C ++ 11 możesz napisać to:
int && z = 12; //C+11 only
Zauważ, że jest
&&
intead of&
. Zauważ również, żeconst
nie jest już potrzebne, mimo że obiekt, z którym sięz
łączy, jest tymczasowym obiektem utworzonym z całki-literału12
.Ponieważ C ++ 11 wprowadził odwołanie do wartości r ,
int&
odtąd nazywane jest odniesieniem do wartości .źródło
12
jest stałą czasu kompilacji, której nie można zmienić w przeciwieństwie do danych, do których się odwołujeint&
. Możesz to zrobićconst int& z = 12;
źródło
void f( vector<int> const & )
, która jest idiomatyczna, aby przekazać wektor, który nie ma być modyfikowany. Problem polega teraz na tymf( vector<int>(5) )
, że byłoby to niepoprawne, a użytkownik musiałby podać inne przeciążenie,void f( vector<int> v ) { f(v); }
które jest trywialne.f( vector<int>(5) )
kompilator utworzy tymczasową, a następnie wiąże odwołanie z tym tymczasowym i podobnie jeśli wystąpiła niejawna konwersja z5
bezpośrednio. Pozwala to kompilatorowi na wygenerowanie pojedynczego podpisu dla funkcji i umożliwia implementację funkcji przez jednego użytkownika. Od tego momentu podobne zachowanie jest definiowane dla pozostałych zastosowań stałych odniesień dla spójności.T const & r = *ptr;
każde późniejsze użycier
w funkcji może zostać zastąpione przez*ptr
ir
nie musi istnieć w czasie wykonywania) lub może być zaimplementowane poprzez zachowanie adresu obiektu, do którego przypisuje aliasy (rozważ przechowywanie referencji jako członka obiektu) - który jest implementowany jako wskaźnik z autodreferencją.Wiązanie odniesienia inne niż stałe i stałe podlega innym regułom
Oto zasady języka C ++:
12
) jest „wartością r”int &ri = 12;
jest źle sformułowanaMusisz zrozumieć, że to są reguły C ++. Po prostu są.
Łatwo jest wymyślić inny język, na przykład C ++, z nieco innymi zasadami. W C ++ byłoby dozwolone utworzenie referencji niebędącej stałą z wartością r. Nie ma tu nic niespójnego ani niemożliwego.
Ale pozwoliłoby to na pewien ryzykowny kod, w którym programista mógłby nie uzyskać tego, co zamierzał, a projektanci C ++ słusznie postanowili uniknąć tego ryzyka.
źródło
Odniesienia to „ukryte wskaźniki” (niezerowe) do rzeczy, które mogą się zmieniać (lvalues). Nie możesz ich zdefiniować jako stałe. Powinna to być rzecz „zmienna”.
EDYTOWAĆ::
Myślę o
int &x = y;
jako prawie odpowiednik
int* __px = &y; #define x (*__px)
gdzie
__px
jest nową nazwą, a#define x
działa tylko wewnątrz bloku zawierającego deklaracjęx
odniesienia.źródło
const
:)const