Je pense que toutes les réponses qui expliquent que vous ne devriez pas avoir un indicateur qui contrôle si une exception est levée ou non sont bonnes. Leurs conseils seraient mes conseils à tous ceux qui ressentent le besoin de poser cette question.
Je tenais cependant à souligner qu'il existe une exception significative à cette règle. Une fois que vous êtes suffisamment avancé pour commencer à développer des API que des centaines d'autres personnes utiliseront, il peut arriver que vous souhaitiez fournir un tel indicateur. Lorsque vous écrivez une API, vous n'écrivez pas seulement aux puristes. Vous écrivez à de vrais clients qui ont de vrais désirs. Une partie de votre travail consiste à les rendre satisfaits de votre API. Cela devient un problème social, plutôt qu'un problème de programmation, et parfois des problèmes sociaux dictent des solutions qui ne seraient pas idéales comme solutions de programmation à elles seules.
Vous pouvez constater que vous avez deux utilisateurs distincts de votre API, dont l'un souhaite des exceptions et l'autre non. Un exemple concret où cela pourrait se produire est avec une bibliothèque qui est utilisée à la fois en développement et sur un système embarqué. Dans les environnements de développement, les utilisateurs voudront probablement avoir des exceptions partout. Les exceptions sont très populaires pour gérer des situations inattendues. Cependant, ils sont interdits dans de nombreuses situations intégrées, car ils sont trop difficiles à analyser autour des contraintes en temps réel. Quand vous vous souciez réellement non seulement de la moyenne temps nécessaire à l'exécution de votre fonction, mais du temps qu'il faut pour un plaisir individuel, l'idée de dérouler la pile à n'importe quel endroit arbitraire est très indésirable.
Un exemple réel pour moi: une bibliothèque de mathématiques. Si votre bibliothèque de mathématiques a une Vector
classe qui prend en charge l'obtention d'un vecteur unitaire dans la même direction, vous devez être en mesure de diviser par l'amplitude. Si la magnitude est 0, vous avez une situation de division par zéro. En développement, vous voulez les attraper . Vous ne voulez vraiment pas surprendre la division par des 0 qui traînent. Lancer une exception est une solution très populaire pour cela. Cela n'arrive presque jamais (c'est un comportement vraiment exceptionnel), mais quand c'est le cas, vous voulez le savoir.
Sur la plate-forme intégrée, vous ne voulez pas de ces exceptions. Il serait plus logique de faire une vérification if (this->mag() == 0) return Vector(0, 0, 0);
. En fait, je vois cela dans du vrai code.
Pensez maintenant du point de vue d'une entreprise. Vous pouvez essayer d'enseigner deux façons différentes d'utiliser une API:
// Development version - exceptions // Embeded version - return 0s
Vector right = forward.cross(up); Vector right = forward.cross(up);
Vector localUp = right.cross(forward); Vector localUp = right.cross(forward);
Vector forwardHat = forward.unit(); Vector forwardHat = forward.tryUnit();
Vector rightHat = right.unit(); Vector rightHat = right.tryUnit();
Vector localUpHat = localUp.unit() Vector localUpHat = localUp.tryUnit();
Cela satisfait les opinions de la plupart des réponses ici, mais du point de vue de l'entreprise, cela n'est pas souhaitable. Les développeurs intégrés devront apprendre un style de codage et les développeurs de développement devront en apprendre un autre. Cela peut être assez embêtant et contraint les gens à une façon de penser. Potentiellement pire: comment allez-vous prouver que la version intégrée n'inclut pas de code d'exception? La version de lancement peut facilement se fondre, se cachant quelque part dans votre code jusqu'à ce qu'une carte d'examen des échecs coûteuse la trouve.
Si, en revanche, vous avez un indicateur qui active ou désactive la gestion des exceptions, les deux groupes peuvent apprendre exactement le même style de codage. En fait, dans de nombreux cas, vous pouvez même utiliser le code d'un groupe dans les projets de l'autre groupe. Dans le cas de l'utilisation de ce code unit()
, si vous vous souciez réellement de ce qui se passe dans un cas de division par 0, vous devriez avoir écrit le test vous-même. Ainsi, si vous le déplacez vers un système embarqué, où vous obtenez simplement de mauvais résultats, ce comportement est "sain". Maintenant, d'un point de vue commercial, je forme mes codeurs une fois, et ils utilisent les mêmes API et les mêmes styles dans toutes les parties de mon entreprise.
Dans la grande majorité des cas, vous souhaitez suivre les conseils des autres: utilisez des idiomes similaires tryGetUnit()
ou similaires pour les fonctions qui ne génèrent pas d'exceptions et renvoient à la place une valeur sentinelle comme null. Si vous pensez que les utilisateurs peuvent vouloir utiliser à la fois le code de gestion des exceptions et le code de non-exception côte à côte dans un même programme, respectez la tryGetUnit()
notation. Cependant, il y a un cas d'angle où la réalité des affaires peut améliorer l'utilisation d'un drapeau. Si vous vous retrouvez dans ce cas d'angle, n'ayez pas peur de jeter les "règles" au bord du chemin. Voilà à quoi servent les règles!