6
votes

Pourquoi utiliser la manipulation des exceptions dans un code apparemment "sûr"?

S'il vous plaît, que quelqu'un m'explique, que peut-on soulever une exception dans ce code?

function CreateBibleNames: TStrings;
begin
  Result := TStringList.Create;
  try
    Result.Add('Adam');
    Result.Add('Eva');
    Result.Add('Kain');
    Result.Add('Abel');
  except
    Result.Free;
    raise;
  end;      
end;


3 commentaires

Quel bit du code vous concerne?


Entre ESSAYER ET SAUF ... J'ai une attitude similaire comme "simsong" ... bonne?


Bien que l'on ne doive pas mettre en œuvre une manipulation des exceptions uniquement pour le souci de celle-ci; Dans le code ci-dessus, une exception est possible. Si on se produit, il y a un moyen NO pour le code d'appel pour effectuer le nettoyage nécessaire (pour éviter une fuite de mémoire); Par conséquent, il est impératif que le code ci-dessus prenne la précaution comme illustré.


8 Réponses :


2
votes

L'exception la plus évidente serait quelles que soient les utilisations Delphes pour un OutofMemoryException . S'il n'y a pas assez de mémoire pour ajouter quelques chaînes à une liste, libérez toute la liste et ré-jeter l'exception.

Cela ressemble à une programmation trop défensive pour faire une liste de noms prédéterminés - en général, si vous obtenez une exception en raison d'être hors de mémoire, toute votre demande est remplie.


2 commentaires

Bien sûr, c'est un exemple très primitif, mais il révèle la pensée avancée ... Devrais-je faire de même? Je ne vois qu'un seul inconvénient: le code est moins lisible ...


Lyborko, moins le code devient primitif, plus il est important d'utiliser l'idiome de manipulation d'exception démontré dans votre question.



4
votes

La seule raison potentielle d'une exception que je peux voir est une exception exceptionnelle et si c'est le cas - tous les paris sont hors de même. À mon avis, il s'agit d'un exemple d'utilisation abusive d'un concept valide.

Utilisation excessive et injustifiée d'essayer sauf les clutters le code et le rend plus difficile à lire


1 commentaires

Ce n'est que plus difficile à lire jusqu'à ce que vous vous familiarisez avec l'essai, sauf idiome pour des fonctions d'usine comme celui indiqué. Ensuite, vous remarquez à peine. S'il y a un constructeur que n'est pas immédiatement suivi d'une déclaration "Essayer", le code a l'air bizarre.



-2
votes

Note latérale intéressante, certains auteurs de Java considèrent désormais la décision d'exiger l'accrochage des exceptions dans pratiquement tous les cas comme une erreur. C'est parce que la plupart des exceptions entraînent vraiment le programme tué, vous permettant ainsi de laisser également le système d'exécution tuer le programme et d'imprimer une trace de pile, plutôt que de forcer le programmeur à attraper l'exception et ... bien, vient d'imprimer quelque chose et tuer le programme.


5 commentaires

Il n'est pas nécessaire d'attraper toutes les exceptions dans la langue Java. Des exceptions vérifiées peuvent être traitées ou déclarées dans la déclaration de méthode. Si une méthode ne gère pas une exception vérifiée, la méthode doit le déclarer à l'aide du mot clé Toucher. Des exceptions non cochées ne doivent pas être manipulées du tout.


Je ne veux pas que vous travailliez sur une sorte de logiciel qui traite de la vie de quelqu'un! Sortir le programme via un crash dans le cas d'une erreur ne devrait jamais être une option, même pour Bonjour, World!


L'exception du code d'utilisateur DELPHI résulte très rarement de la totalité de l'application.


Ce n'est pas un exemple d'exception «attrapé» ... il est immédiatement re-soulevé. Le code est simplement effectué le nettoyage nécessaire (pour empêcher une fuite de mémoire) si une exception se produit. TRY..EXCEPT est une exception Manipulation Construction, pas une exception Catching Construire. Il est trop souvent maltraité comme une exception capture de construction dans la mesure où je préférerais le comportement par défaut de repasser l'exception à moins que cela ne soit explicitement "capturé" dans le bloc sauf (bien sûr, le paiement d'une pinte de sang devrait également être nécessaire. Chaque fois que CatchException est utilisé ^^).


Tofbeer, Manipulation Une exception signifie Fixation Quelle que soit la situation, c'était causé l'erreur. Une fois qu'une exception est manipulée, Il ne devrait y avoir plus de problème . Si vous rencontrez une exception que vous n'ayez pas attendu (et que vous n'avez donc pas écrit de code pour résoudre), comment pouvez-vous vous le gérer? Vous ne savez même pas ce qui s'est passé. Ce n'est pas une bonne idée pour le programme de continuer à courir, surtout lorsque la vie des gens est en jeu, car le programme sera exécuté dans un état incohérent, éventuellement mettre les personnes dans plus Danger.



2
votes

Sans la source de Tstringlist ou de la documentation faisant autorité, vous ne pouvez pas vraiment savoir. Juste à des fins d'illustration, supposons que la Tstringlist soit écrite de telle sorte que lorsque la mémoire soit serrée, elle commence à échanger des portions de la liste vers et à partir du disque, vous permettant de gérer une liste aussi importante que votre disque. Maintenant, l'appelant est également susceptible de la gamme d'erreurs d'E / S: hors de l'espace disque, mauvais bloc rencontré, délai d'attente de réseau, etc.

traite de telles exceptions surkill? Appel de jugement basé sur le scénario. Nous pourrions demander aux programmeurs de la NASA ce qu'ils pensent.


0 commentaires

9
votes

C'est une bonne habitude d'être dans le retour des objets nouvellement construits des fonctions. Dans un scénario plus complexe qu'une liste de chaînes, certains invariants peuvent être brisés ou une autre erreur se produisent, et donc une exception et, dans ce cas, vous souhaitez que la valeur de retour libérée. Plutôt que d'examiner toutes les situations possibles lorsque cela peut se produire, c'est généralement une bonne pratique d'avoir un seul modèle pour renvoyer des objets nouvellement construits et le suivre partout.

De cette façon, lorsque la mise en œuvre des objets que vous construisez des modifications à l'avenir, vous êtes toujours en sécurité s'ils se lancent une exception.


4 commentaires

Mais j'appellerais toujours Freeandnil (résultat). Il est vrai que l'exception est transmise, mais c'est Saffer pour la fonction de retourner nul dans ce cas. Vous ne savez jamais ce qui se passe ensuite et Nil vous signale que le résultat n'est pas valide.


@Runner: Le fait qu'il existe une exception signifie que le résultat est pas retourné. Et il n'y a aucune raison de définir une valeur qui ne sera jamais vue à rien (nil inclus).


Hm je viens de vérifier et vous êtes correct. Intéressant :) Je n'ai jamais remarqué cela, mais c'est probablement parce que je n'écris jamais le code de cette façon.


Même dans ce cas simple. L'appel d'ajout augmentera la liste demandant ainsi plus de mémoire.



12
votes

D'accord, ce code est étrange, je suis d'accord, et je comprends totalement pourquoi il a été écrit de cette façon. Mais il a été écrit de cette façon parce que la prémisse sous-jacente au code est fausse. Le fait que la construction semble étrange devrait être une "odeur de code", et devrait vous dire que quelque chose pourrait ne pas être fait de la meilleure façon possible.

Premièrement, voici pourquoi la construction inhabituelle dans l'essayer ... sauf blocage. La fonction crée une TStringList, mais si quelque chose ne va pas dans le cours du remplissage, la TStringList créé sera "perdue" sur le tas et sera une fuite de mémoire. Donc, le programmeur d'origine était défensive et s'assurait que si une exception se produisait, la Tstringlist serait libérée et l'exception serait à nouveau surélevée. P>

Maintenant ici est la «mauvaise prémisse». La fonction renvoie une instance de TStrings. Ce n'est pas toujours la meilleure façon d'y aller. Renvoyer une instance d'un objet comme celui qui pose la question "Qui va disposer de cette chose que j'ai créée?". Cela crée une situation où il pourrait être facile - sur le côté appelant - d'oublier qu'une instance TRNString a été allouée. P>

une "meilleure pratique" ici est d'avoir la fonction prendre des TRNStrings comme paramètre, puis remplissez l'instance existante. De cette façon, il ne fait aucun doute sur qui possède l'instance (l'appelant) et donc qui devrait gérer sa vie. P>

Donc, la fonction devient une procédure et pourrait ressembler à ceci: P>

procedure CreateBibleNames(aStrings: TStrings);
begin
  if aStrings <> nil then
  begin
    aStrings .Add('Adam');
    aStrings .Add('Eva');
    aStrings .Add('Kain');
    aStrings .Add('Abel');
  end;      
end;


1 commentaires

Chaque fois que quelqu'un crée une instance d'objet, ils appellent une fonction pour renvoyer la nouvelle instance. Cette fonction (généralement appelée Créer ou créexxxx) est un type particulier de fonction (un constructeur); mais une fonction néanmoins. Donc, chaque fois que quelqu'un appelle une telle fonction créée, il est limité de gérer la ressource (c'est-à-dire détruire l'objet si nécessaire). Conseil: N'appelez pas votre procédure `Procédure Créer BIBLENAMES (Astrings: TRNStrings); `... parce que c'est pas ce que ça fait.



4
votes

J'écrirais le code de cette façon, pour plusieurs raisons:

1) En normalisant la recherche de la mémoire de mémoire, il est facile d'inspecter le code source pour voir si quelque chose manque, sans avoir à lire toutes les lignes. Ici, vous venez de voir le .create et remarquez que la manipulation des exceptions est bonne, vous n'avez donc pas à lire la pièce entre essayer ... Sauf.

2) en normalisant la manière dont vous codez les allocations de mémoire, vous n'oubliez jamais de le faire, même si nécessaire.

3) Si vous modifiez plus tard le code source, insérez du code, modifiez comment .ADD fonctionne, remplacez TStringList avec quelque chose d'autre, etc., il ne casse pas ce code.

4) Cela signifie que vous n'avez pas à penser si TstringList.add () lancera des exceptions, ou non, soulagera votre cerveau pour d'autres travaux qui fournissent plus de valeur.


0 commentaires

2
votes

Ce type de code est un modèle classique "usine". Cet exemple est trivial et peut ne pas nécessiter une manipulation des exceptions car elle pourrait soulever des exceptions dans des cas d'angle extrêmes. Mais si le code d'usine est beaucoup plus complexe, il est correct de libérer l'instance créée avant réaménagée toute exception rencontrée, car l'appelant ne peut pas savoir si l'instance a été créée ou non avant l'exception. soulevé. Il est de loin préférable d'assumer que l'instance n'a pas été créée ou libérée si une exception est renvoyée. Les usines sont utiles lorsque l'instance renvoyée peut ne pas être toujours la même (c'est-à-dire une classe dans une hiérarchie donnée), et lorsque les paramètres de création de l'instance sont "Unknonwn" à l'appelant mais pas l'usine. Dans de tels cas, l'appelant ne peut pas passer une instance déjà créée juste pour être "remplie" avec les paramètres appropriés, mais il suffit de demander une instance - bien sûr, il doit être clair que l'appelant devient le "propriétaire" de l'instance créée. .


0 commentaires