80 votes

Comment gérer l'échec dans le constructeur de C++?

Je veux ouvrir un fichier dans un constructeur de classe. Il est possible que l'ouverture pourrait ne plus fonctionner, la construction de l'objet n'a pas pu être terminée. Comment gérer cet échec? Jeter l'exception? Si cela est possible, comment le gérer dans un non-jeter constructeur?

40voto

BЈовић Points 28674

Si une construction de l'objet d'échec, de lever une exception.

L'alternative est terrible. Vous devez créer un indicateur si la construction a réussi, et de vérifier dans chaque méthode.

28voto

Tony D Points 43962

Je veux ouvrir un fichier dans un constructeur de classe. Il est possible que l'ouverture pourrait ne plus fonctionner, la construction de l'objet n'a pas pu être terminée. Comment gérer cet échec? Jeter l'exception?

Oui.

Si cela est possible, comment le gérer dans un non-jeter constructeur?

Vos options sont les suivantes:

  • la refonte de l'application de sorte qu'il n'a pas besoin de constructeurs non-jeter - vraiment, si c'est possible
  • ajouter un drapeau et d'essai pour la réussite de la construction (encore une fois, else throw) à l'intérieur de chaque fonction membre qui peut légitimement être appelé immédiatement après le constructeur.
    • C'est laid et difficile à garder la droite si vous avez un volatile groupe de développeurs qui travaillent sur le code.
    • Vous pouvez obtenir certains moment de la compilation de vérifier ceci en faisant l'objet polymorphically reporter à l'une des deux versions: une avec succès construit une et une erreur de version, mais qui présente l'utilisation du tas de performances et de coûts.
    • Vous pouvez déplacer la charge de l'appelé code pour le destinataire de l'appel par la documentation d'une exigence qu'ils appellent certains "is_valid()" ou fonction similaire avant d'utiliser l'objet: nouveau enclins à faire des erreurs et laid, mais plus encore distribués et hors de contrôle.
    • Vous pouvez faire cela un peu plus facile et plus localisée pour l'appelant si vous soutien à quelque chose comme: if (X x) ... (c'est à dire l'objet peut être évaluée dans un contexte booléen), mais vous ne disposez pas d' x dans le champ de requête pour les détails de l'erreur.
  • demander à l'appelant de fournir un flux ils sont responsables de l'avoir ouvert... (connu sous le nom de l'Injection de Dépendances ou DI)... dans certains cas, cela ne fonctionne pas:
    • vous pouvez toujours avoir des erreurs lorsque vous allez utiliser le flux à l'intérieur de votre constructeur, que faire alors?
    • le fichier lui-même peut-être un détail d'implémentation qui devrait être privé de votre classe, et non exposé à l'appel: si vous souhaitez supprimer cette exigence plus tard? Par exemple: vous pourriez avoir été la lecture d'une table de recherche de précalculées résultats à partir d'un fichier, mais vous avez fait vos calculs si vite il n'y a pas besoin de précalculer - c'est douloureux (parfois même impossible dans un environnement d'entreprise) pour supprimer le fichier à chaque point de l'utilisation du client, et des forces beaucoup plus recompilation plutôt que potentiellement tout simplement de re-lier.
  • la force de l'appelant de fournir un tampon à un échec/réussite/d'erreur variable de condition qui le constructeur définit: par exemple, bool worked; X x(&worked); if (worked) ...
    • ce fardeau et de verbosité attire l'attention et , espérons-le fait que l'appelant beaucoup plus consciente de la nécessité de consulter la variable après la construction de l'objet
  • la force de l'appelant pour construire l'objet via une autre fonction qui peut utiliser les codes de retour et/ou exceptions:
    • if (X* p = x_factory()) ...
    • Smart_Ptr_Throws_On_Null_Deref p_x = x_factory();`
    • X x; // never usable; if (init_x(&x)) ...
    • etc...

En bref, C++ est conçu pour fournir des solutions élégantes à ces sortes de questions: dans ce cas, des exceptions. Si vous restreindre artificiellement-vous de les utiliser, alors il ne faut pas s'attendre à quelque chose d'autre qui n'a moitié aussi bon travail.

(P. S. j'aime passer des variables qui vont être modifiés par pointeur - worked - dessus - je sais que la FAQ lite décourage, mais en désaccord avec le raisonnement. Pas particulièrement intéressé par la discussion à ce sujet, sauf si vous avez quelque chose de pas couverts par la FAQ.)

15voto

jcoder Points 14982

Ma suggestion pour cette situation spécifique, c'est que si vous ne voulez pas un constuctor à l'échec, parce que si ne peut pas ouvrir un fichier, puis d'éviter cette situation. Passer d'un fichier déjà ouvert pour le constructeur si c'est ce que vous voulez, alors il ne peut pas échouer...

4voto

Crazy Eddie Points 23778

Je veux ouvrir un fichier dans un constructeur de classe.

Presque certainement une mauvaise idée. Très peu de cas lors de l'ouverture d'un fichier en cours de construction est appropriée.

Il est possible que l'ouverture pourrait ne plus fonctionner, la construction de l'objet n'a pas pu être terminée. Comment gérer cet échec? Jeter l'exception?

Yep, ce serait la voie.

Si cela est possible, comment le gérer dans un non-jeter constructeur?

Assurez-il possible qu'un objet construit de classe peut être invalide. Cela signifie fournir des routines de validation, aide, etc...ick

4voto

sashoalm Points 10403

Une façon est de lancer une exception. Une autre est d'avoir un 'bool is_open()' ou 'bool is_valid()' functuon qui retourne false si quelque chose n'allait pas dans le constructeur.

Certains commentaires ici disent que c'est mauvais pour ouvrir un fichier dans le constructeur. Je vais souligner que ifstream fait partie de la norme C++ c'est le constructeur suivant:

explicit ifstream ( const char * filename, ios_base::openmode mode = ios_base::in );

Il ne jette pas une exception, mais il a un is_open fonction:

bool is_open ( );

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