Pourquoi ces nouvelles catégories sont-elles nécessaires ? Les dieux du GT21 essaient-ils simplement de nous embrouiller, nous, simples mortels ?
Je n'ai pas l'impression que les autres réponses (aussi bonnes soient-elles pour la plupart) reflètent vraiment la réponse à cette question particulière. Oui, ces catégories et autres existent pour permettre la sémantique des déplacements, mais la complexité existe pour une seule raison. C'est la seule règle inviolable pour déplacer des objets en C++11 :
Tu ne dois te déplacer que lorsque la sécurité est incontestable.
C'est la raison d'être de ces catégories : pouvoir parler de valeurs là où l'on peut s'en écarter en toute sécurité, et parler de valeurs là où ce n'est pas le cas.
Dans la première version des références aux valeurs r, les mouvements se produisaient facilement. Trop facilement. Suffisamment facilement pour qu'il y ait beaucoup de possibilités de déplacer implicitement des choses sans que l'utilisateur le veuille vraiment.
Voici les circonstances dans lesquelles il est possible de déplacer un objet en toute sécurité :
- Lorsqu'il s'agit d'un objet temporaire ou d'un sous-objet de celui-ci. (prvalue)
- Lorsque l'utilisateur a a explicitement dit de le déplacer .
Si vous le faites :
SomeType &&Func() { ... }
SomeType &&val = Func();
SomeType otherVal{val};
À quoi cela sert-il ? Dans les anciennes versions de la spécification, avant l'introduction des 5 valeurs, cela provoquait un mouvement. Bien sûr, c'est le cas. Vous avez passé une référence rvalue au constructeur, et donc il se lie au constructeur qui prend une référence rvalue. C'est évident.
Il n'y a qu'un seul problème : vous n'avez pas demander pour le déplacer. Oh, on pourrait dire que le &&
aurait dû être un indice, mais cela ne change rien au fait qu'il a enfreint la règle. val
n'est pas un temporaire car les temporaires n'ont pas de nom. Vous avez peut-être prolongé la durée de vie du temporaire, mais cela signifie qu'il ne s'agit pas d'un temporaire. temporaire ; c'est comme n'importe quelle autre variable de la pile.
S'il ne s'agit pas d'une mesure temporaire et que vous n'avez pas demandé à être déplacé, alors le déplacement est une mesure temporaire. erronée.
La solution la plus évidente est de faire val
une valeur l. Cela signifie que vous ne pouvez pas vous en éloigner. OK, d'accord ; il est nommé, donc c'est une lvaleur.
Une fois que vous avez fait cela, vous ne pouvez plus dire que SomeType&&
signifie la même chose partout. Vous avez maintenant fait la distinction entre les références de valeurs nominatives et les références de valeurs non nominatives. Eh bien, les références à des valeurs r nommées sont des valeurs l ; c'est la solution que nous avons trouvée plus haut. Alors comment appelons-nous les références à des valeurs r non nommées (la valeur de retour de Func
ci-dessus) ?
Ce n'est pas une valeur l, car on ne peut pas se déplacer à partir d'une valeur l. Et nous besoin pour pouvoir se déplacer en renvoyant un &&
Sinon, comment pourrait-on dire explicitement qu'il faut déplacer quelque chose ? C'est ce que std::move
des retours, en fin de compte. Ce n'est pas une rvalue (à l'ancienne), car elle peut se trouver à gauche d'une équation (les choses sont en fait un peu plus compliquées, voir cette question et les commentaires ci-dessous). Il ne s'agit ni d'une valeur l, ni d'une valeur r ; c'est un nouveau type de chose.
Ce que nous avons, c'est une valeur que l'on peut traiter comme une valeur l, sauf qu'il est implicitement déplaçable. Nous l'appelons une valeur x.
Notez que les valeurs x sont celles qui nous permettent de gagner les deux autres catégories de valeurs :
-
Une valeur pr est en fait simplement le nouveau nom du type précédent de valeur r, c'est-à-dire qu'il s'agit des valeurs r que l'on ne peut pas utiliser. ne sont pas xvaleurs.
-
Les valeurs gl sont l'union des valeurs x et des valeurs l en un seul groupe, parce qu'elles ont beaucoup de propriétés en commun.
En fait, tout se résume aux valeurs x et à la nécessité de restreindre les mouvements à certains endroits précis et seulement à certains endroits. Ces endroits sont définis par la catégorie rvalue ; les prvalues sont les déplacements implicites, et les xvalues sont les déplacements explicites ( std::move
renvoie une valeur x).
0 votes
Les valeurs r et l s'excluent-elles mutuellement ? L'expression
x
oùx
esint
peut être utilisé comme valeur l ou valeur r.9 votes
@Philip Potter : En C++03 ? Oui. Une lvalue peut être utilisée comme rvalue parce qu'il y a une conversion standard de lvalue à rvalue.
1 votes
@Philip (en C++03) La façon dont il est utilisé n'a pas d'importance ; il ne peut s'agir que de l'un des deux. Si vous pouvez l'assigner, c'est une lvalue, sinon, c'est une rvalue. Le fait d'être une valeur l ne signifie pas que vous ne pouvez pas l'utiliser du côté droit d'une expression, et le fait d'être utilisé du côté droit d'une expression ne fait pas en soi de quelque chose une valeur r.
16 votes
@Tyler : "Si vous pouvez l'assigner, c'est une lvalue, sinon, c'est une rvalue". -> Faux, on peut assigner des valeurs r à la classe :
string("hello") = string("world")
.2 votes
En fait, cela fonctionne parce que vous pouvez appeler des membres non-const (tels que
std::string::operator=(std::string const&)
) sur les temporaires. Mais l'affectation à des UDT est un peu difficile à comprendre.4 votes
Notez qu'il s'agit de la catégorie de valeur. Les expressions peuvent avoir d'autres propriétés. Celles-ci comprennent champ de bits (vrai/faux), temporaire (vrai/faux) et type (son type).
1 votes
J'ai trouvé cet article : eli.thegreenplace.net/2011/12/15/ Il pourrait être utile à quelqu'un à l'avenir. Selon moi, il n'est ni trop compliqué ni trop simple. Il va en fait un peu en profondeur/explication mais le fait d'une manière compréhensible. Il mentionne aussi des choses à propos de c++11. hih
31 votes
Je pense que le lien de Fred ci-dessus est meilleur que toutes les réponses données ici. Mais le lien est mort. Il a été déplacé vers : stroustrup.com/terminologie.pdf
84 votes
En C++, même les types ont des types
1 votes
Je constate que vous n'avez pas accepté de réponse ici. Les réponses actuelles ne sont-elles pas satisfaisantes ? Dans l'affirmative, que souhaiteriez-vous voir figurer dans une réponse ?
1 votes
@ShafikYaghmour : J'aime l'ensemble des réponses ; plusieurs d'entre elles contiennent des informations précieuses. Je n'ai pas l'intention d'accepter une réponse. Si vous avez quelque chose à ajouter, n'hésitez pas à le faire.
2 votes
J'ai trouvé ce tutoriel excellent : blog.smartbear.com/development/ (pour l'ensemble de la série, voir blog.smartbear.com/author/danny-kalev )
1 votes
@JamesMcNellis : pourquoi n'avez-vous pas l'intention d'accepter une réponse ? Alors pourquoi avoir posé la question ?
2 votes
@PravasiMeet Comme je l'ai indiqué dans mon commentaire précédent, j'apprécie l'ensemble des réponses. Plusieurs d'entre elles offrent des informations précieuses. Je n'ai pas l'intention d'en choisir une plutôt qu'une autre.
1 votes
Je sais qu'il est un peu tard, mais voici une explication courte et claire : blog.knatten.org/2018/03/09/
1 votes
En fait, en C++11, une valeur est toujours soit un rvaleur ou un valeur . valeur x y valeur pr sont les deux partitions (disjointes) de rvalue, et valeur de la gl est l'union de lvalue et xvalue.
1 votes
Le présent La référence est une grande ressource.
0 votes
Le présent est formidable pour la clarté de ses explications. Photos incluses.
0 votes
Votre question a 1444 votes positifs. Veuillez accepter une réponse pour le tremblement des nouveaux paysans.
0 votes
Mon explication rapide préférée : accu.org/journals/overload/27/150/knatten_2641