0
votes

Renvoie une référence locale à partir de la fonction

J'essaie de comprendre ce qui se passe à l'intérieur avec ce comportement (bizarre?) De g ++.

#include <iostream>
using namespace std;
int& f(void) {
  int a = 9;
  int& b = a;
  return a;
}
int main(void) {
  int& l = f();

  cout << ++l << '\n' << l << '\n';
}

En renvoyant a lui-même et en le liant à l , j'obtiens un avertissement (référence à une variable locale) et un seg.fault si j'y accède à partir de l, mais lorsque je retourne b lui-même, non seulement je n'obtiens pas de seg.fault mais je peux accédez-y une fois depuis l (UB je suppose) avant que la valeur de l change aléatoirement. Mais que se passe-t-il exactement ici?

Les deux retours ne sont-ils pas identiques? Est-ce que g ++ marque automatiquement a's zone de a comme inutilisable après le retour, d'où le seg.fault tout en permettant pour une raison quelconque à b de vivre plus longtemps?


1 commentaires

C'est UB. Inspectez l'assemblage exact et généré ou n'essayez pas de deviner. Il n'y a pas d'explication générale.


3 Réponses :


2
votes

Non, les compilateurs C ++ ne marquent pas les zones comme inutilisables.

Les Segfaults ne sont que l'une des nombreuses façons dont un comportement non défini peut se manifester. C'est en fait l'un des moyens les plus conviviaux, car cela vous fait remarquer tôt.

Vous êtes en charge de la vie. Si vous vous trompez, le résultat est un comportement indéfini. Pas une exception. Pas un segfault. Littéralement n'importe quoi .

Un symptôme possible est «cela semble fonctionner». Un autre est le segfault. D'autres incluent un voyage dans le temps littéral (où UB plus tard dans le programme fait que le code plus efficace se comporte différemment), le disque dur de votre ordinateur est rendu inutilisable, quelqu'un obtient les informations de votre carte de crédit, l'historique de votre navigateur est envoyé par courrier électronique à votre liste de contacts, etc.

Certains compilateurs, en mode débogage, marquent la mémoire désallouée avec un modèle de bits pour faciliter le débogage.


2 commentaires

Cependant, les deux déclarations de retour sont identiques, non? Donc, je suppose que le retour de la référence elle-même ne donne pas d'avertissement / seg.fault car il pourrait également pointer vers quelque chose avec une portée de vie supérieure à la fonction?


@pol One est facile à diagnostiquer pour le compilateur, l'autre un peu plus difficile. Mais ils sont tous les deux UB (une fois que vous utilisez la référence retournée). Les avertissements du compilateur ne sont que des avertissements, ils ne sont ni garantis ni exhaustifs de chaque problème.



2
votes

Votre principale question est de savoir pourquoi gcc n'émet pas d'avertissement dans l'une des alternatives. Les deux alternatives sont un comportement non défini et la seule différence est que dans un cas, le compilateur peut le détecter et vous en avertir.

La norme C ++ ne nécessite pas de diagnostic pour un comportement non défini. Tout diagnostic à cet effet, de votre compilateur, n'est qu'un bonus supplémentaire; et bien que les compilateurs C ++ modernes soient très intelligents, ils ne peuvent pas toujours comprendre que le code compilé entraînera des démons qui sortiront de votre nez .

PS gcc 10.2 émet un avertissement avec l'option -O3 , pour le return b; alternative. Avec -Wall uniquement, gcc émet également un deuxième avertissement pour un comportement non défini, vous pouvez découvrir ce que c'est par vous-même.


1 commentaires

Merci. J'ai également découvert des avertissements clang , ce qui est intéressant!



1
votes

Mais que se passe-t-il exactement ici?

Comportement indéfini.

Les deux retours ne sont-ils pas identiques?

Le code source est clairement syntaxiquement différent. Les programmes n'ont pas la même signification sémantique car aucun des deux programmes n'a de signification sémantique car la signification des deux programmes n'est pas définie. En tant que tel, le comportement des programmes n'est pas garanti d'être le même.

G ++ marque-t-il automatiquement la zone de a comme inutilisable après le retour

Peut-être. Je ne suppose pas que ce soit le cas sur la base de cette seule observation, mais cela peut être vrai. Voir le code source de GCC pour confirmer.


0 commentaires