11
votes

Passez-vous par référence, référence constante, référence de rvalue ou référence de rvalue constante?

J'apprendais passer par référence, et voici le test que j'ai fait: xxx

et voici le résultat que j'ai obtenu: xxx p> Ma question est la suivante:

  1. Si nous passons une expression constante, il déclenche toujours une référence de rvalue non constante? Sous quelle condition il va déclencher une référence de rvalue constante (et pourquoi S6 ne le triggente pas?)

  2. Pourquoi une référence non constante et une référence de rvalue constante sont illégales?

  3. Je m'attendais à ce que cela ne puisse pas changer S3, mais pourquoi B dans la portée intérieure peut changer S3? Si l'attribution d'un nouvel objet S3 à B attribue une nouvelle référence, pourquoi, lorsque j'affecte S4 à elle et S3 a changé et S4 est vide par la suite?

    Désolé de demander trop de questions ... Je vais augmenter les points lorsque toutes les questions sont répondues :) La référence apporte simplement ma confusion du pointeur à un tout nouveau niveau.


    < P> Je ne sais pas comment augmenter le point ... Attendrez donc 2 jours jusqu'à ce qu'il soit éligible à une prime, puis choisissez la réponse.

6 commentaires

Il n'y a pas de Références de références en C ++. La syntaxe && se réfère à une référence de rvalue ou à une référence universelle (dans les modèles).


En référence de la référence, vous voulez dire RValue-Référence. La norme appelle spécifiquement des références aux références ne sont pas autorisées. Juste FYI. C ++ 11 § 8.3.2, P5: "Il n'y aura aucune référence aux références, aucun tableau de références et aucun point de référence de références. ..." abrégé pour .. bien .. Brevity .


@Dyp true, malgré le fait que les références universelles n'existent pas réellement. ;)


"Il déclenche toujours une référence de rvalue constante" non, votre code jamais a déclenché la référence de rvalue constante. Il toujours trigued la référence de rvalue non-const.


La référence non-Const n'est pas illégale. const r-valeur semble un peu bizarre


@MOOINGKUCK UNE AUTRE TYPO. Corrigée


5 Réponses :


6
votes

RValues ​​peut se lier à des références de rvalue et des références Cons-LValue, par exemple xxx pré>

mais la rvalue ne peut pas se lier aux références de lvalue non constituées. La résolution de la surcharge préfère la liaison des temporaires vers RValue-Refs sur les reliures à la const-la liaison à Const Lvalue Refs: P>

paramCheck("");         // a string literal is an lvalue (!)
                        // see [expr.prim.general]/1
                        // but it is implicitly converted to a `std::string`,
                        // creating a `string` temporary, a rvalue

paramCheck(string{""}); // a temporary is an rvalue

string s3{""};
paramCheck(s3);         // the variable `s3` is an lvalue of type `string`

const string s4{""};
paramCheck(s4);         // the variable `s4` is an lvalue of type `const string`

//Illegal
//string& s{""};        // can't bind a temporary to a non-const lvalue ref
//paramCheck(s);

const string& s5{s3};
paramCheck(s5);         // the variable `s5` is a lvalue of type `const string`

string&& s6{""};        // binding a temporary to a rvalue-ref (allowed)
paramCheck(s6);         // the variable `s6` is an lvalue (!) - it has a name

//Illegal
//const string&& s{s1}; // `s1` has not been declared
//onstFP(s);

//Reference test
string a = s3;          // copy the contents of `s3` to a new string `a`
a = "a changed s3";     // overwrite contents of `a`
cout << s3;

{
string& b = s3;         // `b` refers to `s3` now (like an alias)
b = "b changed after assigning s3\n";
cout << "s3 is now " <<s3;

b = s4;                 // copy the contents of `s4` to `b` (i.e. to `s3`)
b = "b changed after assigning s4\n";
cout << "s3 is now " <<s3;
cout << "s4 is now " <<s4;
}


0 commentaires

3
votes

Si nous passons une expression constante, il déclenche toujours une référence de rvalue non constante? Sous quelle condition il va déclencher une référence de rvalue constante (et pourquoi S6 ne le triggente pas?)

Pour une expression constante? Rien. La seule fois où quelque chose se liera à const && sera s'il est déjà const . Et même alors, cela nécessitera une distribution explicite s'il s'agit d'une variable (voir ci-dessous).

Pourquoi une référence non constante et une référence de rvalue constante sont illégales?

Je vais supposer que vous parlez de ceux-ci: xxx

Le premier est illégal car "" n'est pas un std :: chaîne variable. Par conséquent, il doit construire un std :: chaîne temporaire de "" . s est une référence non-const à une chaîne existante variable . Vous ne pouvez pas faire une référence non-const à une référence temporaire, car une variable n'est pas une variable.

La seconde est illégale parce que (ignorant le fait que S1 n'existe pas ) C ++ ne vous permet pas d'obtenir une référence de valeur R à une variable sans conversion explicite . C'est ce que std :: déplacer est pour. const string && s {std :: move (S3)} fonctionne juste bien.

Je m'attendais à ne pas changer S3, mais pourquoi B dans la portée intérieure peut changer S3? Si l'attribution d'un nouvel objet S3 à B est attribuant une nouvelle référence, pourquoi, lorsque j'affecte S4 à elle et S3 a changé et S4 est vide ensuite?

Tout d'abord, vous pouvez modifier S3 bien. B est un référence à S3 ; Ils sont deux noms pour le même objet. Quant au reste, vous ne pouvez pas modifier quel objet est référencé par B après B est créé. B Démarre le référencement de référence S3 , il sera donc toujours le faire. Ainsi, b = s4 signifie copier s4 dans tout objet est référencé par b , qui est s3 .

S4 est vide après parce qu'il était toujours vide . Vous avez attribué la chaîne vide à elle. Donc, c'est vide.


0 commentaires

11
votes

D'abord le code

paramCheck(""); //constructs a temporary. temporaries bind to `string&&`
paramCheck(string{""}); //constructs a temporary. temporaries bind to `string&&`
string s3{""};
paramCheck(s3); //passes a reference to an existing string: `string&`
const string s4{""};
paramCheck(s4); //passes a reference to an existing string+const: `const string&`
//Illegal
//string& s{""}; //cannot assign a temporary to a non-const l-reference
                 //what would s refer to when the temporary "dies"?
                 //`const string&` would have worked though
//paramCheck(s); //passes a reference to an existing string+const: `const string&`
const string& s5{s3}; //s5 is s3, but with `const`. 
paramCheck(s5); //passes a reference to an existing string+const: `const string&`
string&& s6{""}; //r-references extend the life of temporaries.
paramCheck(s6); //passes a reference to an existing strong: `string&`
//const string&& s{s1}; //temporaries can be extended by `T&&` or `const T&` only.

//Reference test
string a = s3; //a is a _copy_ of s3
a = "a changed s3"; //so changing the copy doesn't effect the origional.
cout << s3; //s3 is still blank, it hasn't changed.

{
string& b = s3; //b isn't really a "reference" to `s3`".  `b` _IS_ `s3`.
b = "b changed after assigning s3\n"; //since `b` IS `s3`, this changes `s3`.
cout << "s3 is now " <<s3;

b = s4; //`b` _IS_ `s3`, so you just changed `s3` again.
b = "b changed after assigning s4\n";
cout << "s3 is now " <<s3;
cout << "s4 is now " <<s4; //s4 is still blank, it hasn't changed.
}


6 commentaires

Je n'ai pas l'impression que cela va être considéré comme un commentaire constructif selon les règles de SOF, mais j'ai besoin de dire que j'aime apprendre et effacer des choses à travers vos réponses @MOOKing Duck. Vous expliquez les choses pleinement et d'une manière qui a du sens pour moi. Je sais que je ne suis pas le seul à savoir de cette façon et si mon fonctionnement n'a pas bloqué la fonction de discussion de SOF, je l'aurais fait dans un cadre plus approprié. Mais merci pour l'aide que vous m'avez donnée, que ce soit directement ou non. Mes emails de mon profil et j'aimerais discuter avec vous de codé de temps en temps si vous êtes prêt. :)


"Il existe des moyens de déclencher const string && , mais il n'y a aucune raison de le faire de ce jour, donc ça n'a pas d'importance." homme, c'était une telle déception. Souhaitez-vous expliquer comment de toute façon? :)


@Mehrdad: a édité les deux manières qui se viennent immédiatement à l'esprit dans la question, bien que je suis sûr qu'il y a d'autres. Calling std :: Déplacer sur une variable Conscons fonctionne probablement par exemple. Les trois manières sont assez explicites, vous ne les trouverez probablement pas accidentellement


@MOOINGDUCK: cool, +1.


@Dan: C'est toujours incroyable d'obtenir des commentaires comme ça. Vous vous êtes gagné une citation sur mon profil: D


Depuis que nous avons déjà une référence de const, pourquoi avons-nous besoin de référence de rvalue?



2
votes

Vous devriez arrêter de penser à foo && comme référence de rvalue. Pensez plutôt à ce que les choses se lient.

une fonction prenant foo && ne se liera que pour temporaire foo s, ou foo s marqué comme temporaire.

Ce marquage temporaire ne dure pas. Si vous avez une variable foo && foo , et que vous l'utilisez, il n'est pas marqué comme temporaire au point d'utilisation. Marquer quelque chose comme étant un temporaire ne peut se produire immédiatement - par une fonction qui renvoie un foo && ou en renvoyant un anonyme foo qui, dans son utilisation immédiate, est considéré comme temporaire .

Les moyens standard de marquer des données comme temporaire sont à (a) c'est une instance anonyme de FOO temporaire, (B) que vous avez appelé std :: Déplacer Sur une instance de foo , (c) appelé std :: transfert sur une instance de foo .

En pratique, && est utilisé à la fois par ce que l'on appelle les références universelles et par des références que vous souhaitez lier aux temporaires. Dans un contexte de déduction de type, les références de lvalue peuvent être stockées dans un t && en faisant t dans foo & - la référence de lvalue "gagne" sur le Revalue référence. C'est la situation où vous devez appeler std :: avant afin de déplacer conditionnellement.

En bref: il y a quatre spots valides communs à utiliser && .

  • Lorsque vous prenez un argument, vous souhaitez être déplacé dans une liste de fonctions ou de méthodes.
  • Lorsque vous utilisez un transfert parfait et la technique de référence universelle dans un modèle Les arguments de la fonction.
  • Lorsque vous effectuez une transmission d'un paramètre de transfert parfait à une valeur de retour.
  • Lorsque vous effectuez la technique de référence universelle pour créer une référence à la portée de la fonction peut-être temporaire (par exemple, pour (auto && i: x) ).

    Lorsque vous utilisez une variable nommée && , il agit presque exactement comme un & ou Const & variable. Afin de l'utiliser de manière à traiter comme temporaire, vous devez std :: Déplacer ou dans un contexte de référence universel, utilisez std :: Transférer à Conditionnellement std :: Déplacer .


0 commentaires

4
votes

Juste pour répondre à cette partie:

Sous quelle condition il va déclencher une référence de rvalue constante

La surcharge de référence de rvalue constante sera utilisée lorsque vous l'appelez avec une rvalue de type constant: xxx

dans les fonctions générales prenant un const x && sont inutiles, car vous ne pouvez pas passer d'une constante. Ils peuvent être utiles comme des fonctions supprimées afin d'empêcher certains appels de compilation.


0 commentaires