Les temporaires ne peuvent pas être liés à des références non constantes. int (12) est un temporaire dans ce cas.
Prasoon Saurav
@PrasoonSaurav Qu'entendez-vous par temporaire 12? Manque de concepts ici (de ma part :))
Aquarius_Girl
2
Notez qu'il n'y a pas de raison technique stricte pour cette restriction. Il aurait été tout aussi facile à mettre en œuvre de permettre des références mutables aux temporaires. L'interdire est une décision de conception de C ++, car une telle construction serait une mauvaise conception avec un risque beaucoup plus grand d'être abusé par inadvertance qu'un véritable utilitaire. (Je n'ai trouvé qu'une fois le besoin artificiel d'une telle chose.)
Kerrek SB
@KerrekSB le besoin le plus courant d'une référence de liaison à un objet rvalue est probablement(ostringstream() << "x=" << x).str()
curiousguy
@curiousguy: Oui, c'est le contenu du lien que j'ai publié.
Kerrek SB
Réponses:
132
C ++ 03 3.10 / 1 dit: "Chaque expression est une lvalue ou une rvalue." Il est important de se rappeler que la valeur par rapport à la valeur est une propriété des expressions et non des objets.
Lvalues nomme les objets qui persistent au-delà d'une seule expression. Par exemple, obj, *ptr, ptr[index]et ++xsont tous lvalues.
Les valeurs R sont des valeurs temporaires qui s'évaporent à la fin de l'expression complète dans laquelle elles vivent ("au point-virgule"). Par exemple, 1729, x + y, std::string("meow")et x++sont tous rvalues.
L'opérateur d'adresse de demande que son "opérande doit être une valeur l". si nous pouvons prendre l'adresse d'une expression, l'expression est une lvalue, sinon c'est une rvalue.
" si nous pouvions prendre l'adresse d'une expression, l'expression est une lvalue, sinon c'est une rvalue. " si seulement C ++ était aussi simple! (mais la nuance n'est pas vraiment pertinente ici) "Les valeurs R sont temporaires" quoi? objets?
curiousguy
2
Les @curiousguyRvalues sont des temporaires qui disparaissent à la fin de la pleine expression dans laquelle elles vivent. Pour simplement répondre pourquoi l'express int & = 12;est invalide, le standard dit qu'un littéral de chaîne est une lvalue, les autres littéraux sont des rvalues.
BruceAdi
@curiousguy: Oui. Les valeurs R sont des objets temporaires , mais toutes les valeurs r ne sont pas des objets temporaires; certains ne sont même pas des objets.
Nawaz
" Par exemple, 1729, x + y, std :: string (" meow ") et x ++ sont tous des rvalues. " Mais std::string("meow")construit un objet de type std::stringet renvoie une rvalue qui désigne cet objet, 1729n'a pas d'effet secondaire et donne une valeur 1729 comme rvaleur de type int.
curiousguy
1
@curiousguy: La déclaration "Lvalues name objects that persist beyond a single expression."est une déclaration 100% correcte. Au contraire, votre exemple (const int &)1est incorrect, car ce n'est PAS un objet "nommé".
Nawaz
53
int &z = 12;
Sur le côté droit, un objet temporaire de type intest créé à partir du littéral intégral 12, mais le temporaire ne peut pas être lié à une référence non const. D'où l'erreur. C'est la même chose que:
int &z = int(12); //still same error
Pourquoi un temporaire est créé? Parce qu'une référence doit faire référence à un objet dans la mémoire, et pour qu'un objet existe, il doit d'abord être créé. Puisque l'objet n'est pas nommé, il s'agit d'un objet temporaire . Il n'a pas de nom. À partir de cette explication, il est devenu assez clair pourquoi le deuxième cas est bon.
Un objet temporaire peut être lié à une référence const, ce qui signifie que vous pouvez le faire:
constint &z = 12; //ok
Référence C ++ 11 et Rvalue:
Par souci d'exhaustivité, je voudrais ajouter que C ++ 11 a introduit rvalue-reference, qui peut se lier à un objet temporaire. Donc, en C ++ 11, vous pouvez écrire ceci:
int && z = 12; //C+11 only
Notez qu'il y a au &&lieu de &. Notez également que ce constn'est plus nécessaire, même si l'objet auquel zse lie est un objet temporaire créé à partir d'intégrale-littérale 12.
Depuis que C ++ 11 a introduit rvalue-reference , il int&est désormais appelé lvalue-reference .
@curiousguy, soyez cohérent, vous avez dit "Il faut comprendre que ce sont des règles C ++. Elles existent, et n'ont pas besoin de justification" (sans parler de la première édition). Comment dois-je interpréter votre plainte de ne pas donner ce qui est selon vous n'est pas nécessaire?
Michael Krelin - hacker
2
@ MichaelKrelin-hacker: Techniquement non, vous ne pouvez (jamais) lier une référence à une valeur (ou à une constante de temps de compilation), la norme est assez explicite quant à ce qui se passe réellement: sinon, un temporaire de type «cv1 T1» est créé et initialisé à partir de l'expression d'initialisation en utilisant les règles pour une initialisation de copie sans référence (8.5). La référence est alors liée au temporaire C'est-à-dire que la syntaxe est autorisée, mais la sémantique ne consiste pas à lier une référence à la constante, mais plutôt à la lier au temporaire qui est implicitement créé.
David Rodríguez - dribeas
1
@curiousguy: Les règles de la langue font partie de la conception, et le plus souvent, il y a des justifications pour expliquer pourquoi la langue a été conçue comme telle. Dans ce cas particulier, comme en C, vous n'êtes pas autorisé à prendre l'adresse d'une valeur (elle n'en a pas), ni à lier une référence. Considérons maintenant une fonction void f( vector<int> const & ), qui est idiomatique pour passer un vecteur qui ne doit pas être modifié. Le problème maintenant est que ce f( vector<int>(5) )serait incorrect et que l'utilisateur devrait fournir une surcharge différente, void f( vector<int> v ) { f(v); }ce qui est trivial.
David Rodríguez - dribeas
1
... maintenant parce que cela serait pénible pour les utilisateurs du langage, les concepteurs ont décidé que le compilateur effectuerait l'opération équivalente pour vous, dans l'appel f( vector<int>(5) ), le compilateur crée un temporaire, puis lie la référence à ce temporaire, et de même s'il y avait une conversion implicite de 5directement. Cela permet au compilateur de générer une signature unique pour la fonction et permet une implémentation de la fonction par un seul utilisateur. À partir de là, un comportement similaire est défini pour le reste des utilisations de références constantes pour la cohérence.
David Rodríguez - dribeas
1
@ MichaelKrelin-hacker: les références sont des alias d'objets et une valeur n'est pas un objet. Selon le contexte, les références peuvent être simplement des alias, le compilateur supprime la référence et utilise simplement l'identifiant pour signifier ce que signifie l'objet d'origine ( T const & r = *ptr;, toute utilisation ultérieure de rdans la fonction peut être remplacée par *ptr, et rn'a pas besoin d'exister au moment de l'exécution) ou il peut devoir être implémenté en conservant l'adresse de l'objet qu'il alias (envisagez de stocker une référence en tant que membre d'un objet) - qui est implémenté comme un pointeur auto-référencé.
David Rodríguez - dribeas
4
La liaison de référence non-const et const suit des règles différentes
Voici les règles du langage C ++:
une expression constituée d'un nombre littéral ( 12) est une "rvalue"
il n'est pas permis de créer une référence non-const avec une rvalue: int &ri = 12;est mal formée
il est permis de créer une référence const avec une rvalue: dans ce cas, un objet sans nom est créé par le compilateur; cet objet persistera tant que la référence elle-même existera.
Vous devez comprendre que ce sont des règles C ++. Ils sont juste.
Il est facile d'inventer un langage différent, disons C ++, avec des règles légèrement différentes. En C ++ ', il serait permis de créer une référence non-const avec une rvalue. Il n'y a rien d'incohérent ni d'impossible ici.
Mais cela permettrait un code risqué où le programmeur pourrait ne pas obtenir ce qu'il voulait, et les concepteurs C ++ ont à juste titre décidé d'éviter ce risque.
Les références sont des "pointeurs cachés" (non nuls) vers des choses qui peuvent changer (lvalues). Vous ne pouvez pas les définir comme une constante. Ce devrait être une chose "variable".
ÉDITER::
Je pense à
int &x = y;
comme presque équivalent de
int* __px = &y;
#define x (*__px)
où __pxest un nouveau nom, et les #define xœuvres uniquement à l'intérieur du bloc contenant la déclaration de xréférence.
Oui, je voulais dire votre libellé «les références sont des pointeurs vers des choses qui peuvent changer» - il s'agit de références sans coût.
Michael Krelin - hacker
"Les références sont des" pointeurs cachés " " faux " vers des choses qui peuvent changer de " mauvaises " choses qui peuvent changer (lvalues). " Faux
(ostringstream() << "x=" << x).str()
Réponses:
C ++ 03 3.10 / 1 dit: "Chaque expression est une lvalue ou une rvalue." Il est important de se rappeler que la valeur par rapport à la valeur est une propriété des expressions et non des objets.
Lvalues nomme les objets qui persistent au-delà d'une seule expression. Par exemple,
obj
,*ptr
,ptr[index]
et++x
sont tous lvalues.Les valeurs R sont des valeurs temporaires qui s'évaporent à la fin de l'expression complète dans laquelle elles vivent ("au point-virgule"). Par exemple,
1729
,x + y
,std::string("meow")
etx++
sont tous rvalues.L'opérateur d'adresse de demande que son "opérande doit être une valeur l". si nous pouvons prendre l'adresse d'une expression, l'expression est une lvalue, sinon c'est une rvalue.
&obj; // valid &12; //invalid
la source
int & = 12;
est invalide, le standard dit qu'un littéral de chaîne est une lvalue, les autres littéraux sont des rvalues.std::string("meow")
construit un objet de typestd::string
et renvoie une rvalue qui désigne cet objet,1729
n'a pas d'effet secondaire et donne une valeur 1729 comme rvaleur de typeint
."Lvalues name objects that persist beyond a single expression."
est une déclaration 100% correcte. Au contraire, votre exemple(const int &)1
est incorrect, car ce n'est PAS un objet "nommé".int &z = 12;
Sur le côté droit, un objet temporaire de type
int
est créé à partir du littéral intégral12
, mais le temporaire ne peut pas être lié à une référence non const. D'où l'erreur. C'est la même chose que:int &z = int(12); //still same error
Pourquoi un temporaire est créé? Parce qu'une référence doit faire référence à un objet dans la mémoire, et pour qu'un objet existe, il doit d'abord être créé. Puisque l'objet n'est pas nommé, il s'agit d'un objet temporaire . Il n'a pas de nom. À partir de cette explication, il est devenu assez clair pourquoi le deuxième cas est bon.
Un objet temporaire peut être lié à une référence const, ce qui signifie que vous pouvez le faire:
const int &z = 12; //ok
Référence C ++ 11 et Rvalue:
Par souci d'exhaustivité, je voudrais ajouter que C ++ 11 a introduit rvalue-reference, qui peut se lier à un objet temporaire. Donc, en C ++ 11, vous pouvez écrire ceci:
int && z = 12; //C+11 only
Notez qu'il y a au
&&
lieu de&
. Notez également que ceconst
n'est plus nécessaire, même si l'objet auquelz
se lie est un objet temporaire créé à partir d'intégrale-littérale12
.Depuis que C ++ 11 a introduit rvalue-reference , il
int&
est désormais appelé lvalue-reference .la source
12
est une constante de compilation qui ne peut pas être modifiée contrairement aux données référencées parint&
. Ce que tu peux faire c'estconst int& z = 12;
la source
void f( vector<int> const & )
, qui est idiomatique pour passer un vecteur qui ne doit pas être modifié. Le problème maintenant est que cef( vector<int>(5) )
serait incorrect et que l'utilisateur devrait fournir une surcharge différente,void f( vector<int> v ) { f(v); }
ce qui est trivial.f( vector<int>(5) )
, le compilateur crée un temporaire, puis lie la référence à ce temporaire, et de même s'il y avait une conversion implicite de5
directement. Cela permet au compilateur de générer une signature unique pour la fonction et permet une implémentation de la fonction par un seul utilisateur. À partir de là, un comportement similaire est défini pour le reste des utilisations de références constantes pour la cohérence.T const & r = *ptr;
, toute utilisation ultérieure der
dans la fonction peut être remplacée par*ptr
, etr
n'a pas besoin d'exister au moment de l'exécution) ou il peut devoir être implémenté en conservant l'adresse de l'objet qu'il alias (envisagez de stocker une référence en tant que membre d'un objet) - qui est implémenté comme un pointeur auto-référencé.La liaison de référence non-const et const suit des règles différentes
Voici les règles du langage C ++:
12
) est une "rvalue"int &ri = 12;
est mal forméeVous devez comprendre que ce sont des règles C ++. Ils sont juste.
Il est facile d'inventer un langage différent, disons C ++, avec des règles légèrement différentes. En C ++ ', il serait permis de créer une référence non-const avec une rvalue. Il n'y a rien d'incohérent ni d'impossible ici.
Mais cela permettrait un code risqué où le programmeur pourrait ne pas obtenir ce qu'il voulait, et les concepteurs C ++ ont à juste titre décidé d'éviter ce risque.
la source
Les références sont des "pointeurs cachés" (non nuls) vers des choses qui peuvent changer (lvalues). Vous ne pouvez pas les définir comme une constante. Ce devrait être une chose "variable".
ÉDITER::
Je pense à
int &x = y;
comme presque équivalent de
int* __px = &y; #define x (*__px)
où
__px
est un nouveau nom, et les#define x
œuvres uniquement à l'intérieur du bloc contenant la déclaration dex
référence.la source
const
:)const