Pourquoi est-il déconseillé de renvoyer un pointeur sur une variable ou un paramètre local?

J’ai trouvé cette question dans mon guide d’étude et je ne sais pas pourquoi il serait mauvais de renvoyer un pointeur sur une variable / un paramètre local. Des idées?

Ce n’est pas tant une “mauvaise pratique” (ce qui implique que cela pourrait causer des problèmes), mais plutôt une pratique qui causera absolument un comportement indéfini . C’est comme déréférencer un pointeur nul: ne le faites pas et attendez-vous à ce que votre programme se comporte dans les limites de la logique.

Explication:

Lorsqu’une variable locale (y compris un paramètre) est déclarée, une mémoire automatique lui est atsortingbuée, ce qui signifie que le compilateur se charge d’allouer de la mémoire pour la variable, puis de la désaffecter sans aucun effort de la part du programmeur.

void foo(int bar) { int baz; } //baz and bar dissappear here 

Lorsque la durée de vie de la variable se termine (par exemple, lorsque la fonction revient), le compilateur remplit sa promesse et toutes les variables automatiques locales à la fonction sont détruites. Cela signifie que tous les pointeurs sur ces variables pointent maintenant vers une mémoire résiduelle que le programme considère comme “libre” pour faire ce qu’il veut.

Lors du renvoi d’une valeur, ce n’est pas un problème: le programme trouve un nouvel emplacement pour mettre la valeur.

 int foo(int bar) { int baz = 6; return baz + bar; //baz + bar copied to new memory location outside of foo } //baz and bar disapear 

Lorsque vous retournez un pointeur, sa valeur est copiée normalement. Cependant, le pointeur pointe toujours vers le même emplacement qui est maintenant garbage :

 int* foo(int bar) { int baz = 6; baz += bar; return &baz; //(&baz) copied to new memory location outside of foo } //baz and bar disapear! &baz is now garbage memory! 

Accéder à cette mémoire est un comportement indéfini, de sorte que votre programme va très probablement mal se comporter d’une manière ou d’une autre. Par exemple, j’ai déjà été victime de ce problème et, bien que mon programme ne se soit pas arrêté ou arrêté, mes variables ont commencé à se dégrader en valeurs parasites à mesure que le compilateur remplaçait la mémoire “libre”.

Parce que cela causera un comportement indéfini dans votre programme.

Si vous renvoyez un pointeur sur une variable locale une fois que la fonction a renvoyé, sa scope est hors de scope. Dès lors, le comportement n’est pas défini si vous accédez au pointeur renvoyé.

Une fois que la fonction est revenue, les variables et parameters locaux, qui étaient sur la stack, ont été désaffectés. Ils existent peut-être toujours, mais il n’y a aucune garantie, et quand quelque chose décidera d’utiliser la stack, ils seront certainement bousillés.

En utilisant le diagramme de WP:

Diagramme de pile

Le pointeur de stack en haut est l’endroit où de nouvelles variables peuvent être affectées et placées en toute sécurité (par exemple, lors de l’appel d’une fonction). Lorsque la fonction (par exemple, DrawLine) est renvoyée, elle est retirée de la stack (le pointeur de la stack est simplement incrémenté de sorte qu’il ne pointe plus sur des variables en dehors de la scope, vertes,). Tout ce qui arrive plus tard et alloue et utilise de la stack détruira les anciennes valeurs.

Une variable locale est stockée sur la stack. Les valeurs stockées dans la stack sont détruites une fois que la fonction / le bloc de code est quitté (vous atteignez la fin d’une fonction – techniquement, elles peuvent durer plus longtemps, mais c’est une autre discussion). Par conséquent, le pointeur (qui pointe vers une adresse située à un emplacement particulier dans la mémoire) pointe vers une valeur qui peut ne plus exister.

Parce que l’adresse de cette variable appartient au cadre de stack à partir duquel elle a été créée. Rien d’autre. Une fois que vous return , cet enregistrement d’activation est nettoyé et tout ce qui s’y trouvait auparavant est maintenant indéfini.