En lisant cette explication sur les lvalues et les rvalues, ces lignes de code me sont apparues:
int& foo(); foo() = 42; // OK, foo() is an lvalue
Je l’ai essayé en 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 comstack bien, mais le lancer donne une erreur de segmentation . Juste la ligne
int& foo();
en soi, à la fois comstack et fonctionne sans aucun problème.
que veut dire ce code? Comment pouvez-vous atsortingbuer une valeur à un appel de fonction et pourquoi n’est-ce pas une valeur?
L’explication suppose qu’il existe une implémentation raisonnable pour foo
qui renvoie une référence lvalue à un int
valide.
Une telle implémentation pourrait être:
int a = 2; //global variable, lives until program termination int& foo() { return a; }
Maintenant que foo
renvoie une référence lvalue, nous pouvons atsortingbuer quelque chose à la valeur de retour, comme ceci:
foo() = 42;
Cela mettra à jour le global a
avec la valeur 42
, que nous pouvons vérifier en accédant directement à la variable ou en appelant à nouveau foo
:
int main() { foo() = 42; std::cout << a; //prints 42 std::cout << foo(); //also prints 42 }
Toutes les autres réponses déclarent une statique à l’intérieur de la fonction. Je pense que cela pourrait vous tromper, alors regardez ceci:
int& highest(int & i, int & j) { if (i > j) { return i; } return j; } int main() { int a{ 3}; int b{ 4 }; highest(a, b) = 11; return 0; }
Puisque la valeur la highest()
renvoie une référence, vous pouvez lui atsortingbuer une valeur. Lorsque ceci s’exécute, b
passera à 11. Si vous avez modifié l’initialisation de sorte que a
soit, par exemple, 8, alors a
serait changé à 11. Ceci est un code qui pourrait effectivement servir à une fin, contrairement aux autres exemples.
int& foo();
Déclare une fonction nommée foo qui renvoie une référence à un int
. Ce que ces exemples échouent à faire, c’est vous donner une définition de cette fonction que vous pourriez comstackr. Si nous utilisons
int & foo() { static int bar = 0; return bar; }
Maintenant, nous avons une fonction qui renvoie une référence à la bar
. Puisque la barre est static
elle restra active après l’appel à la fonction. Maintenant si nous faisons
foo() = 42;
Ce qui se passe est que nous assignons 42 à la bar
puisque nous assignons à la référence et que la référence est juste un alias pour la bar
. Si nous appelons à nouveau la fonction comme
std::cout << foo();
Il imprimerait 42 puisque nous avons mis cette bar
au dessus.
int &foo();
déclare une fonction appelée foo()
avec le type de retour int&
. Si vous appelez cette fonction sans fournir de corps, vous risquez d’obtenir une erreur de référence non définie.
Dans votre deuxième tentative, vous avez fourni une fonction int foo()
. Ceci a un type de retour différent de la fonction déclarée par int& foo();
. Vous avez donc deux déclarations du même foo
qui ne correspondent pas, ce qui viole la règle de définition unique provoquant un comportement indéfini (aucun diagnostic requirejs).
Pour quelque chose qui fonctionne, sortez la déclaration de fonction locale. Ils peuvent conduire à un comportement indéfini et 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 à:
int &foo() { static int i = 2; return i; } int main() { ++foo(); std::cout << foo() << '\n'; }
int& foo();
est une fonction renvoyant une référence à int
. Votre fonction fournie renvoie int
sans référence.
Vous pouvez faire
int& foo() { static int i = 42; return i; } int main() { int& foo(); foo() = 42; }
int & foo();
signifie que foo()
renvoie une référence à une variable.
Considérez ce code:
#include int k = 0; int &foo() { return k; } int main(int argc,char **argv) { k = 4; foo() = 5; std::cout << "k=" << k << "\n"; return 0; }
Ce code imprime:
$ ./a.out k = 5
Parce que foo()
renvoie une référence à la variable globale k
.
Dans votre code révisé, vous transformez la valeur renvoyée en référence, qui est alors invalide.
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 suis pas sûr que vous ayez déjà travaillé avec des pointeurs, mais c’est une idée similaire, vous ne retournez pas la valeur de la fonction – au lieu de cela, vous transmettez les informations nécessaires pour trouver l’emplacement en mémoire. int est.
Donc, pour résumer, vous n’atsortingbuez 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 posez la question – la raison pour laquelle vous obtenez une erreur de segmentation est due au fait que vous retournez un littéral numérique “2” – c’est donc l’erreur exacte que vous auriez si vous définissiez un const int et que vous essayiez ensuite de modifier son valeur.
Si vous ne vous êtes pas encore familiarisé avec les pointeurs et la mémoire dynamic, alors je vous conseille de le faire car il existe quelques concepts difficiles à comprendre, à moins que vous ne les appreniez tous en même temps.
L’exemple de code de la page liée est simplement une déclaration de fonction factice. Il ne comstack 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 valeur convertie en lvalue. Ceci est clairement déterminé à échouer. Vous pourriez faire:
int& foo() { static int x; return x; }
et réussirait en changeant la valeur de x, en disant:
foo() = 10;
La fonction que vous avez, foo (), est une fonction qui renvoie une référence à un entier.
Alors disons à l’origine que foo a renvoyé 5, et plus tard, dans votre fonction principale, vous dites foo() = 10;
, puis imprime foo, il imprimera 10 au lieu de 5.
J’espère que cela à du sens 🙂
Je suis nouveau à la programmation aussi. C’est intéressant de voir des questions comme celle-ci qui vous font réfléchir! 🙂