Il y a littéralement des livres entiers écrits sur ce sujet, donc toute réponse sera au mieux un résumé. Voici quelques points importants qui, selon moi, méritent d’être soulignés, en fonction de votre question. Ce n'est pas une liste exhaustive.
Les exceptions ne sont PAS destinées à être capturées partout.
Tant qu'il existe un gestionnaire d'exceptions général dans la boucle principale - en fonction du type d'application (serveur Web, service local, utilitaire de ligne de commande ...) - vous disposez généralement de tous les gestionnaires d'exceptions dont vous avez besoin.
Dans mon code, il n'y a que quelques déclarations catch, voire aucune, en dehors de la boucle principale. Et cela semble être l'approche commune du C ++ moderne.
Les exceptions et les codes de retour ne sont pas mutuellement exclusifs.
Vous ne devriez pas en faire une approche du tout ou rien. Les exceptions doivent être utilisées pour des situations exceptionnelles. Des choses comme "Fichier de configuration introuvable", "Disque plein" ou toute autre chose qui ne peut pas être gérée localement.
Les échecs courants, tels que la vérification de la validité d'un nom de fichier fourni par l'utilisateur, ne constituent pas un cas d'utilisation d'exceptions; Utilisez plutôt une valeur de retour dans ces cas.
Comme vous le voyez dans les exemples ci-dessus, "fichier non trouvé" peut être une exception ou un code retour, selon le cas d'utilisation: "fait partie de l'installation" par rapport à "l'utilisateur peut créer une faute de frappe".
Donc, il n'y a pas de règle absolue. Une directive approximative est la suivante: s’il peut être manipulé localement, faites-en une valeur de retour; si vous ne pouvez pas le gérer localement, lancez une exception.
La vérification statique des exceptions n'est pas utile.
Comme les exceptions ne doivent de toute façon pas être gérées localement, les exceptions pouvant être levées n’ont généralement pas d'importance. La seule information utile est de savoir si une exception peut être levée.
Java a une vérification statique, mais cela est généralement considéré comme une expérience manquée et la plupart des langages depuis - notamment le C # - ne disposent pas de ce type de vérification statique. C’est une bonne lecture des raisons pour lesquelles C # ne l’a pas.
Pour ces raisons, C ++ a déconseillé son utilisation throw(exceptionA, exceptionB)
en faveur de noexcept(true)
. Le paramètre par défaut est qu'une fonction peut lancer, de sorte que les programmeurs doivent s'y attendre, sauf indication contraire explicite de la documentation.
L'écriture de code sécurisé d'exception n'a rien à voir avec l'écriture de gestionnaires d'exceptions.
Je dirais plutôt que l'écriture de code sécurisé d'exception consiste à éviter d'écrire des gestionnaires d'exception!
La plupart des meilleures pratiques visent à réduire le nombre de gestionnaires d'exceptions. Écrire du code une fois et l'invoquer automatiquement - par exemple via RAII - entraîne moins de bogues que le copier-coller du même code partout.