263 votes

Quand faut-il qu'un constructeur lève une exception ?

Quand un constructeur doit-il lever une exception ? (Ou dans le cas de l'Objective C : quand est-il bon pour un init'er de retourner nil ?)

Il me semble qu'un constructeur devrait échouer -- et donc refuser de créer un objet -- si l'objet n'est pas complet. C'est-à-dire que le constructeur devrait avoir un contrat avec son appelant pour fournir un objet fonctionnel sur lequel les méthodes peuvent être appelées de manière significative ? Est-ce raisonnable ?

6voto

Michael L Perry Points 2380

En raison de tous les problèmes qu'une classe partiellement créée peut causer, je dirais jamais.

Si vous devez valider quelque chose pendant la construction, rendez le constructeur privé et définissez une méthode statique publique de la fabrique. La méthode peut lancer un appel si quelque chose n'est pas valide. Mais si tout se vérifie, elle appelle le constructeur, qui est assuré de ne pas être rejeté.

7 votes

Je dirais que c'est le contraire - si nous ne voulons pas d'objets partiellement créés, le constructeur debe lorsqu'il y a un problème - de cette façon, l'appelant saura que quelque chose a mal tourné.

1 votes

@TimBezhashvyly : Parce que ça ne correspond pas à la réalité. Dans le monde réel, certains échecs ne peuvent pas être prédits, seulement détectés.

0 votes

@BenVoigt ce n'est pas une excuse.

5voto

blowdart Points 28735

C'est toujours assez douteux, surtout si vous allouez des ressources à l'intérieur d'un constructeur ; selon votre langage, le destructeur ne sera pas appelé, et vous devrez donc nettoyer manuellement. Cela dépend de la date à laquelle la durée de vie d'un objet commence dans votre langue.

La seule fois où je l'ai vraiment fait, c'est lorsqu'il y a un problème de sécurité quelque part qui fait que l'objet ne devrait pas, plutôt qu'il ne peut pas, être créé.

0 votes

Je n'ai aucune idée de la raison pour laquelle quelqu'un a noté cela... Pour moi, il me semble que c'est une bonne chose à prendre en compte lorsque l'on lance une exception dans un constructeur. Je suis sûr qu'il y a plus que quelques projets avec des fuites de mémoire parce que le destructeur n'a pas été appelé après avoir lancé une exception.

2 votes

C'est moi qui ai voté contre. Dans n'importe quel langage, le principe de responsabilité unique s'applique : si un objet est responsable de la gestion d'une ressource, il ne devrait rien faire d'autre, et donc le seul cas où son constructeur se lance est lorsqu'il échoue à obtenir la ressource. Chaque langage que je connais détruit de manière fiable les objets entièrement construits, donc ces ressources seront prises en charge. Vous n'aurez des problèmes que si vous voulez qu'un objet gère plus d'une ressource manuellement, et c'est une erreur. Le problème n'est pas de lancer des constructeurs.

5voto

Matt Dillard Points 9040

Il est raisonnable qu'un constructeur lève une exception tant qu'il se nettoie correctement. Si vous suivez la méthode RAII paradigme (l'acquisition des ressources est l'initialisation) alors il es Il est assez courant qu'un constructeur fasse un travail significatif ; un constructeur bien écrit nettoiera à son tour après lui-même s'il ne peut pas être complètement initialisé.

3 votes

@cgreen revérifiez les dates sur ces posts, s'il vous plaît. Cet article de blog date du 3 décembre 2008 - l'article ci-dessus date du 16 septembre 2008 - ou presque. trois mois avant que cet article de blog n'existe .

0 votes

@cgreeno : Comment peut-il être copié alors que ce billet a été fait trois mois avant ce billet de blog ?

0 votes

@JeffAtwood J'ai vérifié deux fois les dates avant de poster le commentaire. Les dates des articles de blog sont parfois modifiées pour les rendre plus pertinents. Cependant, je vais retirer le commentaire pour éviter toute controverse, car je pourrais m'être trompé et je n'ai aucune preuve de cela.

4voto

Nick Points 1818

Si vous écrivez des contrôles d'interface utilisateur (ASPX, WinForms, WPF, ...), vous devez éviter de lancer des exceptions dans le constructeur car le concepteur (Visual Studio) ne peut pas les gérer lorsqu'il crée vos contrôles. Connaissez le cycle de vie de vos contrôles (événements de contrôle) et utilisez l'initialisation paresseuse lorsque cela est possible.

3voto

moonshadow Points 28302

Voir les sections FAQ C++ 17.2 y 17.4 .

En général, j'ai constaté que le code est plus facile à porter et à maintenir si les constructeurs sont écrits de manière à ne pas échouer, et si le code qui peut échouer est placé dans une méthode séparée qui renvoie un code d'erreur et laisse l'objet dans un état inerte.

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X