En lisant cette explication sur les valeurs lvalues et rvalues, ces lignes de code me sont apparues:
int& foo();
foo() = 42; // OK, foo() is an lvalue
Je l'ai essayé dans g ++, mais le compilateur dit "référence indéfinie à foo ()". Si j'ajoute
int foo()
{
return 2;
}
int main()
{
int& foo();
foo() = 42;
}
Il compile bien, mais son exécution donne une erreur de segmentation . Juste la ligne
int& foo();
par lui-même à la fois compile et s'exécute sans aucun problème.
que veut dire ce code? Comment attribuer une valeur à un appel de fonction et pourquoi n'est-ce pas une rvalue?
c++
function
return-by-reference
Sossisos
la source
la source
Réponses:
L'explication suppose qu'il existe une implémentation raisonnable pour
foo
laquelle renvoie une référence lvalue à une valeur valideint
.Une telle implémentation pourrait être:
Maintenant, puisque
foo
renvoie une référence lvalue, nous pouvons assigner quelque chose à la valeur de retour, comme ceci:Cela mettra à jour le global
a
avec la valeur42
, que nous pouvons vérifier en accédant directement à la variable ou en appelant àfoo
nouveau:la source
Toutes les autres réponses déclarent un statique à l'intérieur de la fonction. Je pense que cela pourrait vous dérouter, alors jetez un œil à ceci:
Étant donné que
highest()
renvoie une référence, vous pouvez lui attribuer une valeur. Quand cela s'exécute,b
sera changé en 11. Si vous avez changé l'initialisation de sorte quea
c'était, disons, 8, alorsa
serait changé en 11. C'est un code qui pourrait en fait servir un but, contrairement aux autres exemples.la source
Déclare une fonction nommée foo qui renvoie une référence à un
int
. Ce que ces exemples ne parviennent pas à faire, c'est de vous donner une définition de cette fonction que vous pourriez compiler. Si nous utilisonsNous avons maintenant une fonction qui renvoie une référence à
bar
. puisque bar est,static
il vivra après l'appel à la fonction, il est donc sûr de lui renvoyer une référence. Maintenant si nous faisonsCe qui se passe, c'est que nous attribuons 42 à
bar
puisque nous attribuons à la référence et que la référence n'est qu'un alias pourbar
. Si nous appelons à nouveau la fonction commeIl imprimerait 42 puisque nous avons défini
bar
celui ci-dessus.la source
int &foo();
déclare une fonction appeléefoo()
avec le type de retourint&
. Si vous appelez cette fonction sans fournir de corps, vous obtiendrez probablement une erreur de référence non définie.Dans votre deuxième tentative, vous avez fourni une fonction
int foo()
. Cela a un type de retour différent de la fonction déclarée parint& foo();
. Vous avez donc deux déclarations identiquesfoo
qui ne correspondent pas, ce qui enfreint la règle d'une définition, provoquant un comportement indéfini (aucun diagnostic requis).Pour quelque chose qui fonctionne, supprimez la déclaration de fonction locale. Ils peuvent conduire à un comportement indéfini silencieux comme vous l'avez vu. Au lieu de cela, utilisez uniquement des déclarations de fonction en dehors de toute fonction. Votre programme pourrait ressembler à:
la source
int& foo();
est une fonction renvoyant une référence àint
. Votre fonction fournie est renvoyéeint
sans référence.Vous pouvez faire
la source
int & foo();
signifie quefoo()
renvoie une référence à une variable.Considérez ce code:
Ce code imprime:
$ ./a.out k = 5
Parce que
foo()
renvoie une référence à la variable globalek
.Dans votre code révisé, vous convertissez la valeur renvoyée en référence, qui est alors invalide.
la source
Dans ce contexte, le & signifie une référence - donc foo renvoie une référence à un int, plutôt qu'à un int.
Je ne sais pas si vous avez déjà travaillé avec des pointeurs, mais c'est une idée similaire, vous ne renvoyez pas réellement la valeur hors de la fonction - au lieu de cela, vous transmettez les informations nécessaires pour trouver l'emplacement en mémoire où cela int est.
Donc, pour résumer, vous n'attribuez pas de valeur à un appel de fonction - vous utilisez une fonction pour obtenir une référence, puis vous affectez la valeur référencée à une nouvelle valeur. Il est facile de penser que tout se passe en même temps, mais en réalité, l'ordinateur fait tout dans un ordre précis.
Si vous vous demandez - la raison pour laquelle vous obtenez une erreur de segmentation est parce que vous renvoyez un littéral numérique '2' - c'est donc l'erreur exacte que vous obtiendriez si vous deviez définir un const int puis essayer de le modifier valeur.
Si vous n'avez pas encore appris sur les pointeurs et la mémoire dynamique, je vous le recommanderais d'abord car il y a quelques concepts que je pense difficiles à comprendre à moins que vous ne les appreniez tous en même temps.
la source
L'exemple de code sur la page liée n'est qu'une déclaration de fonction factice. Il ne compile pas, mais si vous aviez défini une fonction, cela fonctionnerait généralement. L'exemple signifiait "Si vous aviez une fonction avec cette signature, vous pourriez l'utiliser comme ça".
Dans votre exemple,
foo
renvoie clairement une lvalue basée sur la signature, mais vous retournez une rvalue qui est convertie en lvalue. Ceci est clairement déterminé à échouer. Vous pourriez faire:et réussirait en changeant la valeur de x, en disant:
la source
La fonction que vous avez, foo (), est une fonction qui renvoie une référence à un entier.
Donc, disons qu'à l'origine foo a renvoyé 5, et plus tard, dans votre fonction principale, dites-vous
foo() = 10;
, puis affiche foo, il affichera 10 au lieu de 5.J'espère que cela à du sens :)
Je suis également nouveau dans la programmation. C'est intéressant de voir des questions comme celle-ci qui font réfléchir! :)
la source