De retour à l'école il y a plus de 10 ans, ils vous apprenaient à utiliser des spécificateurs d'exception. Puisque je suis un des programmeurs C de Torvaldish qui évitent obstinément le C ++ sauf à y être contraint, je ne me retrouve que sporadiquement dans C ++, et j'utilise toujours des spécificateurs d'exception, car c'est ce que l'on m'a appris.
Cependant, la majorité des programmeurs C ++ semblent se désintéresser des spécificateurs d'exception. J'ai lu le débat et les arguments de divers gourous du C ++, comme ceux-ci . Autant que je sache, cela se résume à trois choses:
- Les spécificateurs d'exception utilisent un système de types incohérent avec le reste du langage ("système de types d'ombre").
- Si votre fonction avec un spécificateur d'exception renvoie autre chose que ce que vous avez spécifié, le programme sera arrêté de manière incorrecte et inattendue.
- Les spécificateurs d'exception seront supprimés dans la prochaine norme C ++.
Est-ce que je manque quelque chose ici ou sont-ce toutes les raisons?
Mes propres opinions:
En ce qui concerne 1): Et alors? C ++ est probablement le langage de programmation le plus incohérent jamais créé, en termes de syntaxe. Nous avons les macros, les goto / labels, la horde (comportement?) Du comportement indéfini / non spécifié / défini par l'implémentation, les types entiers mal définis, toutes les règles de promotion des types implicites, les mots clés de cas spéciaux tels que ami, auto , inscrivez-vous, explicite ... Et ainsi de suite. Quelqu'un pourrait probablement écrire plusieurs gros livres de toutes les bizarreries en C / C ++. Alors, pourquoi les gens réagissent-ils contre cette incohérence particulière, qui constitue un défaut mineur par rapport à de nombreuses autres caractéristiques beaucoup plus dangereuses de la langue?
Concernant 2): N'est-ce pas ma propre responsabilité? Il y a tellement d'autres façons de rédiger un bogue fatal en C ++, pourquoi ce cas particulier est-il pire? Au lieu d'écrire throw(int)
puis de lancer Crash_t, je peux aussi bien affirmer que ma fonction renvoie un pointeur sur int, puis créer un typecast sauvage et explicite et renvoyer un pointeur sur un Crash_t. L’esprit du C / C ++ a toujours été de laisser la plupart des responsabilités au programmeur.
Qu'en est-il des avantages alors? Le plus évident est que si votre fonction essaie de jeter explicitement un type différent de celui que vous avez spécifié, le compilateur vous donnera une erreur. Je crois que la norme est claire à ce sujet (?). Les bogues ne se produiront que lorsque votre fonction appellera d'autres fonctions qui jetteront le mauvais type.
Venant d’un monde de programmes C embarqués déterministes, je préférerais certainement savoir exactement quelle fonction me lancera. Si quelque chose dans le langage le supporte, pourquoi ne pas l'utiliser? Les alternatives semblent être:
void func() throw(Egg_t);
et
void func(); // This function throws an Egg_t
Je pense qu'il y a de grandes chances pour que l'appelant ignore / oublie de mettre en œuvre le test de capture dans le second cas, moins dans le premier cas.
Si je comprends bien, si l’une ou l’autre de ces deux formes décide de lever soudainement un autre type d’exception, le programme se bloquera. Dans le premier cas, parce qu'il n'est pas autorisé de lancer une autre exception, dans le second, parce que personne ne s'attendait à ce qu'il lance un SpanishInquisition_t et que, par conséquent, cette expression ne soit pas interceptée comme elle aurait dû l'être.
Dans ce dernier cas, avoir une capture de dernier recours (...) au plus haut niveau du programme ne semble pas vraiment mieux qu'un crash de programme: "Hé, quelque part dans votre programme, quelque chose a lancé une exception étrange et non gérée . ". Vous ne pouvez pas récupérer le programme une fois que vous êtes si éloigné de l'exception, la seule chose à faire est de quitter le programme.
Et du point de vue de l'utilisateur, ils se moquaient bien de recevoir une boîte de message malveillante de l'OS disant "Programme terminé. Blablabla à l'adresse 0x12345" ou une boîte de message maléfique de votre programme disant "Exception non gérée: myclass. func.something ". Le bug est toujours là.
Avec la prochaine norme C ++, je n'aurai d'autre choix que d'abandonner les spécificateurs d'exception. Mais je préférerais entendre des arguments solides sur la raison pour laquelle ils sont mauvais, plutôt que "Sa Sainteté l'a dit et c'est ainsi". Peut-être y at-il plus d’arguments contre eux que ceux que j’ai énumérés ou peut-être plus qu’ils ne le pensent?
Réponses:
Les spécifications d'exception sont mauvaises parce qu'elles sont faiblement appliquées, et donc ne font pas grand-chose, mais elles sont également mauvaises parce qu'elles forcent l'exécution à rechercher des exceptions inattendues afin qu'elles puissent terminer () au lieu d'appeler UB. , cela peut entraîner une perte de performance significative.
En résumé, les spécifications d'exception ne sont pas suffisamment imposées dans le langage pour rendre le code plus sûr, et les implémenter de la manière spécifiée a été une lourde perte de performances.
la source
Une des raisons pour lesquelles personne ne les utilise est que votre principale hypothèse est fausse:
Ce programme compile sans erreurs ni avertissements .
De plus, même si l'exception aurait été interceptée , le programme se termine toujours.
Edit: pour répondre à un point de votre question, catch (...) (ou mieux, catch (std :: exeption &) ou une autre classe de base, puis catch (...)) est toujours utile, même si vous ne l'utilisez pas. sais exactement ce qui s'est mal passé.
Considérez que votre utilisateur a appuyé sur un bouton de menu pour "enregistrer". Le gestionnaire du bouton de menu invite l'application à enregistrer. Cela pourrait échouer pour une multitude de raisons: le fichier se trouvait sur une ressource réseau qui avait disparu, il y avait un fichier en lecture seule et il ne pouvait pas être sauvegardé, etc. il ne se soucie que de son succès ou de son échec. Si cela réussit, tout va bien. Si cela échoue, il peut en informer l'utilisateur. La nature exacte de l'exception n'est pas pertinente. De plus, si vous écrivez un code correct et exempt d'exceptions, cela signifie qu'une telle erreur peut se propager à travers votre système sans la détruire - même pour un code qui ne s'en soucie pas. Cela facilite l'extension du système. Par exemple, vous enregistrez maintenant via une connexion à une base de données.
la source
Cet entretien avec Anders Hejlsberg est assez célèbre. Dans ce document, il explique pourquoi l'équipe de conception de C # a tout d'abord ignoré les exceptions vérifiées. En résumé, il y a deux raisons principales: la version et l'évolutivité.
Je sais que l'OP se concentre sur le C ++ alors que Hejlsberg discute de C #, mais les arguments avancés par Hejlsberg sont parfaitement applicables au C ++.
la source