12
votes

Utilisera un goto causer des fuites de mémoire?

J'ai un programme dans lequel je dois sortir d'un grand groupe de boucles imbriquées. Jusqu'à présent, la plupart des gens me disent de le faire est d'utiliser un goto laids dans mon code.

Maintenant, si je crée un tas de pile locale (je pense que c'est ce qu'on appelle, sinon, je veux dire juste des variables régulières sans utiliser la nouvelle commande) Variables à l'intérieur de mes boucles et mon programme frappe une instruction si une instruction qui déclenche Le goto, vais-je rencontrer une fuite de mémoire en raison de mon programme sortant de nombreuses boucles de manière incorrecte et ne pas nettoyer les variables locales?


13 commentaires

Vous ne feuilletez pas de mémoire avec ces autos (ce que vous avez appelé Stack). Mais s'il vous plaît ne pas utiliser goto.


Quel est le problème avec goto?


Question associée: Stackoverflow.com/questions/1257744


@Martinho Fernandes: Je sens que vous découragez l'utilisation des déclarations de goto :) Avoir une histoire à partager?


Oui. Les sauts aller-retour que seuls ne sont pas mauvais. Je les aime beaucoup mieux que de vérifier les variables à chaque boucle. Ils sont également très bons pour la gestion des erreurs des sorties de la fonction C.


@zan Lynx: En fait, c'était la raison entière, j'utilise des gotos. L'objectif était de détecter une fracture par zéro et le retour à l'utilisateur que quelque chose n'allait pas avec le jeu de données. Si l'ensemble de données était correct, vous ne rencontreriez pas ce problème, sinon, les données sont fausses et que le programme doit arrêter le traitement et passer à autre chose.


Si vous réagissez à quelque chose comme une fracture par zéro, vous voudrez peut-être envisager de jeter une exception à la place.


Peut-être que j'étais un peu dur dans les commentaires. J'admets là-bas peut y avoir quelques niches étaient goto n'est pas (beaucoup) nocif. Mais ensuite j'aime citer le premier commentaire de cette réponse: Stackoverflow.com/questions/1024361/... . "+1: Si c'est assez complexe pour prendre en compte un goto, il est assez complexe d'encapsuler dans une fonction et d'éviter le goto."


@ D.Shawley: Oui ... Je ne sais pas ce que ce sont ceux-là ... lol


@MARTINHO: Faites d'abord attention aux déclarations de couverture car: "Les déclarations de couverture sont toujours erronées";) Dans la réponse à la question 1024361, la structure du programme résultant est aussi complexe que si goto avait été utilisée, le code utilise "retour" plutôt que 'goto' mais l'effet est le même. Une différence est que la boucle est maintenant séparée de l'appelant, ce qui rend potentiellement plus difficile de comprendre ce que la fonction fait réellement.


Pensez à retour à partir d'un goto . Si un renvoie fuirait, alors un goto . (Et ceux que vous y êtes, envisagez d'utiliser l'approche structurée au lieu de la spaghetti, mettez ce code dans sa propre fonction et rompez à l'aide d'un retour . La règle des citations de Martinho est géniale. )


@SBI: Une façon de lire votre commentaire est que vous impliquez: "Goto peut être utilisé pour créer du code spaghetti par conséquent tout code qui utilise Goto est le code Spaghetti". Est-ce vraiment ce que vous voulez dire? Les deux principaux arguments à la couverture Ban Goto sont ce qui est ci-dessus (qui est assez médiocre TBH) et le fait que GOTO affecte la structure du programme. Cependant, l'argument de programmation structuré s'applique également à des éléments tels que «Break», «continuer» et «retour». Pourquoi singulier 'goto'? Bien sûr, «goto» peut être mal utilisé mais peut donc presque tous les traitements de la langue d'éveye!


@Richard: Si je vois break , retour et d'autres "gotos structurés", je vois au premier coup d'œil où ils sautent. Ils sont donc beaucoup plus faciles à comprendre que goto .


10 Réponses :


0
votes

Non, vous ne le ferez pas.

Cependant, assurez-vous que des ressources externes sont correctement libérées. Par exemple, si vous avez ouvert un fichier, il serait possible de passer au-delà de l'endroit où il serait normalement fermé.


0 commentaires

0
votes

Nope. Les variables locales n'ont pas besoin d'être nettoyées individuellement. Lorsque la pile apparaît, toutes les variables locales s'en vont bien avec elle.


0 commentaires

2
votes

non. Vous ne pouvez que fuir la mémoire qui est allouée de manière dynamique.


3 commentaires

Vous pouvez fuir la mémoire d'une autre manière. Allouer quelques douzaines de mégaoctets sur une pile de fil, puis allez vous coucher pendant un certain temps, par exemple :)


+1, Hobodave. Vous êtes le premier à me faire craquer aujourd'hui.


Faken n'a pas demandé si la variable de pile elle-même serait divulguée, il a demandé s'il y aurait des fuites comme une conséquence de la variable de pile n'étant pas nettoyée. S'il avait utilisé Longjmp au lieu de goto et que l'une de ses variables a été un vecteur, il y aurait une fuite (de la mémoire allouée dynamiquement cachée derrière l'objet local). Dans ce cas, la réponse pourrait être donnée «Oui. Vous ne pouvez que fuir la mémoire qui est allouée de manière dynamique». Je pense donc que certaines explications du oui / non seraient utiles ;-)



2
votes

Les variables de pile sont définies (et allouées) au moment où vous entrez la fonction et que vous éliminez implicitement le moment où vous quittez la fonction (puisque l'enregistrement complet de la pile d'appel est éclairé). Aucune quantité de rebond à l'intérieur de la fonction ne peut éventuellement causer tout HAVOC avec la mémoire qui a été allouée tout le temps. Quel que soit le chemin d'exécution du code, l'enregistrement de pile apparaîtra lorsque le contrôle revient à la fonction d'appel et la mémoire sera libérée.


4 commentaires

Oui, mais que se passe-t-il si je n'utilise pas de fonction? Est-ce également vrai si j'utilise Goto pour sortir de nombreuses boucles à la fois dans mon programme principal?


Tout est dans une fonction, même si cette fonction est principale (). L'enregistrement de pile pour le principal () est attribué lorsque le programme démarre et supprimé lorsque le programme se termine - les mêmes règles que pour toute autre fonction.


En C ++ et C, votre code fonctionne toujours dans une seule fonction ou une autre. Cette fonction peut être principale () bien sûr.


Ce n'est pas vrai: les variables sont éclairées et hors de la pile tout au long d'une «portée». Jetez un coup d'œil à cet extrait: CODEPAD.ORG/ONCMPFTP



1
votes

Goto n'est pas toujours mauvais, mais dans votre cas, vous ne devriez probablement pas utiliser goto.

Voir des exemples d'une bonne utilisation de goto ici et ici . P>

si Vous goto une étiquette en dehors de la portée de votre objet sur la pile sera libérée. p>

Exemple: P>

#include <iostream>
using namespace std;

class A
{
public:
  ~A() 
  {
     cout<<"A destructor"<<endl;
  }
};



int main(int argc, char**argv)
{
  {
    A a;
    cout<<"Inside scope"<<endl;
    goto l;
    cout<<"After l goto"<<endl;
  }

  cout<<"Outside of scope before l label"<<endl;

l:
  cout<<"After l label"<<endl;
  return 0;
}


2 commentaires

Bien sûr, vous avez raison, mais la rapidité de l'appel de destruction n'est pas indiquée par cette sortie. Peut-être ajouter Cout's's autour de l'étiquette "L"?


@xtofl: Bonne idée, j'ai ajouté des plus de coutures pour clarifier



20
votes

non, vous ne causerez pas de fuite de mémoire. à l'aide d'un goto ne "sortir de manière incorrecte de manière incorrecte". C'est juste pas généralement recommandé d'un point de vue de la structure de code.

Cela de côté, lorsque vous quittez la boucle, les variables locales sortent de la portée et seront sautées de la pile (c'est-à-dire nettoyée) dans le processus.


1 commentaires

Pour quitter une boucle tôt, vous pouvez: (a) utiliser un goto avec une étiquette. (b) Utilisez un objet de condition de boucle supplémentaire, déclarée avant la boucle et vérifié dans la déclaration conditionnelle de chaque boucle. (c) Semblable à 'B' mais vérifiez que le statut de l'objet de condition "pause" si nécessaire. Enfin (d) Vous avez divisé la fonction en deux et utilisez un retour pour sauter hors de la boucle. IMHO, une seule d'entre elles souligne clairement l'intention de l'auteur du code. Un avantage supplémentaire est que GOTO le rend infidèle à la recherche de ces situations rares et peut donc être révisée par des pairs.



0
votes

Non, aucune variables automatiques de vos boucles ne causera pas de fuites de programmation si vous rompez vos boucles avec une déclaration GOTO.


0 commentaires

1
votes

Les autres réponses sont vraies ... Cependant, si vous devez nicher des boucles qui différemment, je remetterais la conception qui les pose là-bas. Entrantant cette logique dans des fonctions distinctes serait un meilleur moyen de résoudre un tel problème.

BILLY3


4 commentaires

Oui, je interroge ma logique à l'aide d'un tableau 5D aussi, mais ce qui fonctionne, fonctionne. Je ne sais pas, l'ensemble du programme commence comme une boucle géante pour commencer et il ne cesse de bouleverser une balle entière de choses sur un ensemble de données.


... A 5D Array? La seule justification que j'ai jamais eue pour cela est dans PHP où les tableaux et l'objet peuvent aussi bien être la même chose à des fins de stockage de données ... Sérieusement, de quoi avez-vous besoin d'un tableau 5D en C pour?


Par conséquent, comme un étranger lui donne la bienvenue. Il y a plus de choses dans le ciel et la terre, Horatio, que de rêve de votre philosophie.


@MMatthew Schaarley: Je traite quelque chose de s'apparentant à une image bitmap (mais instaurée de 3 couleurs par pixel, ses différents attributs, sa part d'un projet plus scientifique). Le fichier lui-même n'est vraiment qu'un tableau 3D, mais lorsque j'ai besoin de traiter des morceaux carrés à la fois, c'est donc à la fin, il se termine plus comme un tableau 5D. 2 Dimensions pour la grille X-Y grossière, puis une autre 2D pour les positions X-Y fines de chaque point de la grille grossière, puis une dimension finale pour les données d'attribut à chaque point ... c'est désordonné de dire le moins. La pire partie de celui-ci était de comprendre la fructure Strucutre ... qui était l'enfer ...



6
votes

Les variables de pile (Autos, non autobots) ne sont pas "fuieuses" comme des variables allouées via New () ou Malloc ().

En ce qui concerne la "laidness" des gotos qui ne sont que dogmatiques. Lire Knuth, il était aussi brillant que Dijkstra. http://ppplab.snu.ac.kr/courses/ adv_pl05 / papiers / p261-knuth.pdf Évitez la programmation basée sur les pâtes, mais une utilisation prudente ne dégradra pas dans des spaghettis.

Dijkstra ne les a pas aimés parce que la majeure partie de ce que vous pouvez faire avec des gotos peut être effectuée avec d'autres techniques de programmation structurées et utilise moins de code, rendant ainsi l'autre silex structuré moins d'erreur.

Comprendre que les gotos ne devraient pas être votre première solution, et ne sortez pas de votre façon de les utiliser, mais si cela a du sens, ne vous soumettez pas aux mobs de la chaîne dogmatique. La déclaration de pause est un goto à déguisement conçu pour des cas où le commandement strict adhésif au commandement "tu n'utilise pas de gotos" n'a pas eu de sens.


8 commentaires

Dijkstra ne les aimait pas parce que l'utilisation habituelle de chacun était une barrière à l'adoption d'une programmation structurée. La pause n'est pas "GOTO DANS DISGUISE", alors sinon «goto in déguisé». Ce sont toutes des constructions de programmation structurées qui entraînent un transfert de contrôle non séquentiel.


La pause enfreint les critères «Single Eved» que Dijkstra aime tellement. Il vous abandonne hors du milieu d'une construction bien structurée telle qu'une boucle, qui a une seule entrée et une sortie simple. Une pause doit être utilisée en conjonction avec une évaluation conditionnelle pour être pratique. Si GOTO était le type de déclaration Dijstra voulait remplacer par une programmation structurée. Si casse est la construction identique où la seule différence est que goto a été remplacée par une pause. La pause ne considère que marginly mieux qu'un goto pour ces cas car vous êtes limité dans l'endroit où la pause peut goto.


La pause est considérablement "meilleure" que de goto, car précisément la raison qu'il n'y a qu'un seul endroit où la pause peut aller. Ces limitations sont exactement ce qui distingue la programmation structurée comme une innovation. "GOTO DANS DISCUISE" n'est plus qu'un Slur McCarthyite - Tout le monde peut trouver une similitude entre absolument tout contrôle de flux et "goto". Mais cela n'est guère pertinent de savoir si la technique en question fournit une structure pour aider à la compréhension du code. La terminaison de boucle avec la pause fait exactement cela.


Lorsque vous augmentez l'utilisation de la déclaration de GoTo, vous augmentez la complexité du programme. Vous ne pouvez pas simplement regarder la condition de la boucle pour déterminer quel état de la variable est lorsque vous quittez la boucle. C'était spécifiquement les objections de Dijkstra, ce n'est pas mon opinion que c'est dans son journal et s'applique également à la déclaration de pause. Dijkstra était très académique, pratiquement si une utilisation ultérieure, elle a un effet négatif sur votre analyse de capacité Le comportement de votre programme, mais une application minutieuse dans les cas seulement nécessaires ne peut être utile. Et cela s'applique à la fois aux goto et aux pauses


Votre lecture de "Aller à la déclaration considérée comme nuisible" peut-être différente de celle de la mienne. Je ne pense pas que la pause est une "utilisation débridée d'aller à" rendant "terriblement difficile de trouver un ensemble significatif de coordonnées pour décrire les progrès de processus", car la pause est intrinsèquement bridée à sa boucle. Je l'applique "soigneusement" chaque fois qu'il y a plusieurs critères pour mettre fin à la boucle, qui sont naturellement calculés à différents moments. Ce n'est pas absolument nécessaire, vous pourriez faire des travaux redondants afin de collecter tous les tests en une seule "tandis que" ou "pour". Mais imo c'est presque toujours moins clair.


À l'intérieur d'une structure de bouclage déterminant l'état du logiciel à la sortie de la sortie de la sortie, devient insoluble directement proportionnelle au nombre de pauses ou de gotos lorsqu'il est utilisé dans la logique imbriquée. Cependant, les pauses sont un peu plus sûres en raison du fait qu'il est "bridé" à la boucle. Dijkstra a évoqué la cofination d'une preuve mathématique avec chaque programme écrit, c'est au cœur de sa philosophie. La complexité analytique d'une pause ne correspondrait pas à ses idéaux d'élégance mathématique. Encore une fois, j'adore Dijkstra était très académique, favorisant la correction de la productivité et de l'efficacité.


Bien sûr, et en général, il est proportionnel au nombre de branches (bien ou l'exposant du nombre). Il ne fait aucune différence pour l'analyse si les succursales sont générées par "goto", "pause", "alors que" ou "si", autre que celle de ces "pause" et "si" ne génère que des branches avant. Si vous ou Dijkstra prétendez que tandis que (condition && blah) {quelque chose (); if (bla) autre (); } est plus facile à analyser formellement que alors que (condition) {quelque chose (); Si (! bla) casses; autre chose(); } , alors vous le faites.


Tout ce qu'il réalise formellement est de s'assurer que la post-condition de la boucle est complètement exprimée dans la condition tandis que () et ne nécessite pas de prise en compte des conditions à chaque pause. Mais les deux sont structurellement équivalents (une fois que vous avez effectué le travail supplémentaire dans la case sans pause pour comprendre le flux de données que bla == False entraîne une sortie). C'est juste un cas de prendre le booléen ou des deux états de programme qui quittent la boucle au lieu du booléen ou des deux conditions pouvant échouer à «Bien que». Donc, c'est sur lequel est plus facile - analyse de flux de données ou de contrôle de contrôle.



0
votes

Ressources de fuites aller-retour? Ou tout autre problème potentiel avec le code ci-dessous?

REEXECTE: P>

        try
        {
            //Setup request
            HttpWebRequest request = (HttpWebRequest)WebRequest.Create(url);

            ....

            //Get Response
            HttpWebResponse response = (HttpWebResponse)request.GetResponse();

           if(response != HttpStatus.OK && noOfRetries < 3)
            {
                noOfRetries++;
                Thread.Sleep(10 * 1000);


                response.Close();
                goto Reexecute;
            }
            ...

            response.Close();
         }
         catch
         {

         }


0 commentaires