en regardant du code, je suis tombé sur:
throw /*-->*/new std::exception ("//...
et j'ai toujours pensé que vous n'avez pas besoin / que vous ne devriez pas utiliser new
ici.
Quelle est la bonne manière, les deux sont-ils OK, si oui, y a-t-il une différence?
BTW d'après ce que je peux voir en "grepping" avec PowerShell, les bibliothèques boost ne l'utilisent jamais throw new
.
PS aussi j'ai trouvé du code CLI qui utilise throw gcnew
. Est-ce que ça va?
throw gcnew
serait utile par exemple. si vous voulez que le code managé intercepte votre exception. Quelqu'un peut-il me corriger là-dessus?System::Exception
est généralement une référence à un objet managé sur le tas de récupération de place. J'ai toujours jetégcnew
et attrapé avecSystem::Exception ^
. Bien sûr, j'utilise égalementfinally
tout le temps en C ++ / CLI, bien que je ne me mélange pas souvent avec des exceptions C ++ dans le mêmetry
bloc, je ne sais pas pourquoi.Réponses:
La manière conventionnelle de lancer et d'intercepter des exceptions est de lancer un objet d'exception et de l'attraper par référence (généralement
const
référence). Le langage C ++ nécessite que le compilateur génère le code approprié pour construire l'objet d'exception et le nettoyer correctement au moment opportun.Lancer un pointeur vers un objet alloué dynamiquement n'est jamais une bonne idée. Les exceptions sont censées vous permettre d'écrire du code plus robuste face aux conditions d'erreur. Si vous lancez un objet d'exception de la manière conventionnelle, vous pouvez être sûr que s'il est intercepté par une clause catch nommant le type correct, par un
catch (...)
, s'il est ensuite relancé ou non, il sera détruit correctement au moment approprié. (La seule exception étant si elle n'est jamais interceptée du tout mais c'est une situation irrécupérable quelle que soit la façon dont vous la regardez.)Si vous lancez un pointeur vers un objet alloué dynamiquement, vous devez être sûr que quel que soit l'aspect de la pile d'appels au moment où vous souhaitez lever votre exception, il existe un bloc catch qui nomme le type de pointeur correct et a l'
delete
appel approprié . Votre exception ne doit jamais être interceptée àcatch (...)
moins que ce bloc ne relance l'exception qui est ensuite interceptée par un autre bloc catch qui traite correctement l'exception.En fait, cela signifie que vous avez utilisé la fonction de gestion des exceptions qui devrait faciliter l'écriture de code robuste et rendu très difficile l'écriture de code correct dans toutes les situations. Cela laisse de côté le problème qu'il sera presque impossible d'agir en tant que code de bibliothèque pour le code client qui n'attendra pas cette fonctionnalité.
la source
Pas besoin d'utiliser
new
lors de la levée d'exception.Ecrivez:
et attraper comme:
Notez que cela
yourexception
doit dériverstd::exception
directement ou indirectement.la source
new
? Pourquoi tireryourexception
destd::exception
?throw std::exception;
fonctionne pas ? g ++ ne semble pas le compiler ...std::exception
est un type, et vous ne pouvez pas lancer un type , vous devez lancer un objet . La syntaxe devrait donc être la suivante:throw std::exception();
cela compilera. Maintenant, à quel point c'est bon, est une question complètement différente.Le lancement
new std::exception
est correct si le site d'appel s'attend à attraper un fichierstd::exception*
. Mais personne ne s'attendra à attraper un pointeur vers une exception. Même si vous documentez ce que fait votre fonction et que les gens lisent la documentation, ils sont toujours susceptibles d'oublier et d'essayer d'attraper une référence à unstd::exception
objet à la place.la source
new std::exception
n'est correct que si le site d'appel s'attend à attraper un pointeur ET s'attend à prendre en charge la gestion de l'exception d'allocation ET il n'y aura jamais de cas où votre fonction sera appelée par quelque chose qui n'attrape pas explicitement le bon pointeur (catch(...)
ou aucune manipulation du tout) sinon il y aura une fuite d'objet. En bref, cela peut être approximé comme "jamais".La FAQ C ++ a une belle discussion à ce sujet:
Fondamentalement, "à moins qu'il n'y ait une bonne raison de ne pas le faire, attraper par référence. Évitez d'attraper par valeur, car cela entraîne une copie et la copie peut avoir un comportement différent de celui qui a été lancé. Ce n'est que dans des circonstances très spéciales que vous devez attraper par pointeur. "
la source
A
est distinct du type,A*
donc si je le fais,throw A()
je ne peux PAS attrapercatch(A* e)
car il est de type complètement différent.L'opérateur new ne peut garantir qu'il ne déclenchera jamais d'exception. Pour cette raison, l'utiliser pour lancer une exception "valide" (intentionnelle) produirait un code dont on ne peut garantir qu'il ne plantera pas. Puisqu'il ne peut y avoir qu'une seule exception à la fois et que votre programme essaie d'en lancer deux avant qu'aucune d'entre elles ne puisse être interceptée, la meilleure chose qu'une implémentation puisse faire est d'abandonner immédiatement votre programme, par exemple en appelant std :: terminate.
la source