La capture d'exception: division par zéro
Le code suivant n'est pas d'attraper une exception, lorsque j'essaie de diviser par 0. Dois-je lancer une exception, ou ne l'ordinateur automatiquement jeter un au moment de l'exécution?
int i = 0;
cin >> i; //what if someone enters zero?
try {
i = 5/i;
}
catch (std::logic_error e) {
cerr << e.what();
}
- Pourquoi ne pas vérifier si
i
est égal à zéro ou pas? - Pourquoi êtes-vous en essayant de diviser par ze— OH SHI—
- Non, pas vraiment, j'ai édité ma question.
- Cette question et toutes les réponses qui a suivi sont une belle étude de tout ce qui est faux avec des exceptions.
Vous devez vous connecter pour publier un commentaire.
Vous devez vérifier vous-même et de lever une exception. Integer division par zéro n'est pas une exception dans la norme C++.
Ni de virgule flottante de division par zéro, mais au moins qui a des moyens spécifiques pour traiter avec lui.
Les exceptions énumérées dans la norme ISO sont:
et on pourrait dire tout à fait convaincante que soit
overflow_error
(l'infini généré par IEEE754 virgule flottante pourrait être considéré comme dépassement de capacité) oudomain_error
(il est un problème avec la valeur d'entrée) serait l'idéal pour indiquer une division par zéro.Toutefois, l'article
5.6
(deC++11
, bien que je ne pense pas que cela a changé à partir de l'itération précédente) précise:Donc, il pourrait jeter ceux (ou autre) des exceptions. Il pourrait également formater votre disque dur et de rire de dérision 🙂
Si vous vouliez mettre en œuvre une telle bête, vous pouvez utiliser quelque chose comme
intDivEx
dans le programme suivant (en utilisant le débordement de la variante):Ce sorties:
et vous pouvez le voir, il jette et intercepte l'exception de la division par zéro cas.
La
%
équivalent est presque exactement le même:std::bad_alloc
qui est générée parnew
domain_error
être plus approprié de jeter ici?std::domain_error
est la bonne à jeter ici, puisque la divisiona / b
est bien défini, sauf dans le domaineb = 0
.domain_error
est un type delogic_error
, qui est généralement liée à des choses que vous devriez être en mesure de détecter au moment de la compilation. Vous ne savez pas si une division par zéro est couvert car vous ne pouvez pas savoir le dénominateur est égal à zéro jusqu'à ce moment de l'exécution. Cependant, j'ai ajouté qu'en tant qu'autre possibilité.Mis à jour avec les commentaires de ExcessPhase
GCC (au moins la version 4.8) vous permettra d'émuler ce comportement:
Ce met en place un nouveau gestionnaire de signal qui déclenche une exception, et une
shared_ptr
à l'ancien gestionnaire de signal, avec une "suppression" fonction qui restaure l'ancien gestionnaire quand elle est hors de portée.Vous avez besoin de compiler avec au moins une de ces options:
Visual C++ vous permettra aussi de faire quelque chose de similaire:
Et bien sûr, vous pouvez ignorer tout le C++11-ishness de cette et les mettre dans un traditionnel RAII-gestion des struct.
std::signal
Pour autant que je sais C++ spécifications ne mentionne rien au sujet de division par zéro exeption. Je crois que vous devez le faire vous-même...
Vous avez besoin de jeter l'exception manuellement à l'aide de
throw
mot-clé.Exemple:
Vous devriez vérifier si
i = 0
et de ne pas diviser ensuite.(Éventuellement après vérification, vous pouvez jeter une exception et de les traiter plus tard).
Plus d'infos sur: http://www.cprogramming.com/tutorial/exceptions.html
setjmp
+longjmp
https://stackoverflow.com/a/25601100/895245 mentionné la possibilité ou jeter une des exceptions C++ à partir d'un gestionnaire de signal, mais La levée d'une exception à l'intérieur d'un gestionnaire de signal mentionne plusieurs mises en garde, donc je serais très prudent.
Comme un autre potentiellement dangereux possibilité, vous pouvez également essayer d'utiliser l'ancienne C
setjmp
+longjmp
mécanisme, tel que montré à: C poignée de signal SIGFPE et de continuer l'exécutionCompiler et exécuter:
De sortie:
man longjmp
dit que vous pouvezlongjmp
de gestionnaires de signaux, mais avec quelques bémols:Voir aussi: Longjmp de gestionnaire de signal?
Cependant La levée d'une exception à l'intérieur d'un gestionnaire de signal mentionne que cela a plus de dangers avec C++:
de sorte que vous devez être très très prudent avec cela.
Je crois que la morale est que les gestionnaires de signaux sont durs, et vous devriez les éviter autant que possible, sauf si vous savez exactement ce que vous faites.
Détecter floating point zéro de la division
Il est également possible de détecter à virgule flottante de la division par zéro avec une glibc appel à:
comme illustré à: Quelle est la différence entre le calme de NaN et de signalisation NaN?
De ce fait, il soulève SIGFPE ainsi comme la division entière par zéro au lieu de simplement en silence qnan et définissant des indicateurs.
do i need to throw an exception or does the computer automatically throws one at runtime?
Soit vous en avez besoin pour
throw
l'exception de vous-même etcatch
il. par exemple,Ou
catch
l'exception qui est levée par votre code.Dans votre cas, je ne suis pas sûr si est-il un standard exception signifiait pour diviser par zéro. Si il n'y a aucune exception, alors vous pouvez utiliser,
Il vous suffit de faire
assert(2 * i != i)
qui lancera une assertion. Vous pouvez écrire votre propre classe d'exception si vous avez besoin de quelque chose de fantaisiste.assert(i != 0)
? Je ne pense pas à travers la frontière des cas, mais si ce n'est pas trivial de voir que l'affirmation est indiqué correctement, alors vous ne devriez pas mettre.assert
est souvent désactivé dans le code de production en raison de la présence deNDEBUG
-assert()
est généralement un développement de la seule méthode pour attraper des problèmes. En tout cas, lancer une affirmation est pas lancer une exception. La première abandonner votre programme plutôt que de générer quelque chose que vous pouvez prendre.