5 votes

Gestion des erreurs en C++, constructeurs et méthodes ordinaires

J'ai un cheesesales.txt Un fichier CSV contenant toutes mes ventes récentes de fromage. Je veux créer une classe CheeseSales qui peuvent faire des choses comme celles-ci :

CheeseSales sales("cheesesales.txt"); //has no default constructor
cout << sales.totalSales() << endl;
sales.outputPieChart("piechart.pdf");

Le code ci-dessus suppose qu'aucune défaillance ne se produira. En réalité, des défaillances se produiront. Dans ce cas, deux types d'échecs peuvent se produire :

  • Échec dans le Constructeur : Le fichier n'existe peut-être pas, n'a peut-être pas les autorisations de lecture, contient des données non valides/non analysables, etc.
  • Échec dans le méthode habituelle : Le fichier peut déjà exister, il se peut qu'il n'y ait pas d'accès en écriture, trop peu de données de vente disponibles pour créer un graphique circulaire, etc.

Ma question est simple : comment concevriez-vous ce code pour gérer les échecs ?

Une idée : Renvoyer un bool de la méthode habituelle indiquant un échec. Je ne sais pas comment gérer le constructeur.

Comment les codeurs C++ expérimentés font-ils ce genre de choses ?

0voto

amosJi Points 46

Je pense que vous pouvez obtenir les informations du fichier d'entrée avant de construire un objet. Par exemple, le code peut être comme :

if(!getInfoFromFile("cheesesales.txt", date, amount, kindOfCheese, money)){
    cout << "Failed to get information from file." << endl;
    return FALSE;
}
CheeseSales sales(date, amount, kindOfCheese, money);
cout << sales.totalSales() << endl;
sales.outputPieChart("piechart.pdf");

Vous pouvez alors éviter de gérer les erreurs dans le constructeur.
Bien sûr, la levée d'une exception est également une solution. Mais je n'aime pas ça car les exceptions en C++ sont très complexes. Vous pouvez rencontrer beaucoup de problèmes inimaginables.

0voto

Anton Golov Points 1953

Vous avez omis un détail important en posant cette question : que voulez-vous qu'il se passe lorsque l'opération échoue ?

Je lancerais certainement une exception dans le cas du constructeur. J'aimerais pouvoir écrire du code comme celui que vous avez écrit ci-dessus ; je ne veux pas qu'il ressemble à ceci

CheeseSales sales("cheesesales.txt"); //has no default constructor
if (!sales.good()) {
    // Somehow handle things here.
}
// The if block has to break control flow or reinitialise sales, otherwise
// these next lines will break.
cout << sales.totalSales() << endl;
sales.outputPieChart("piechart.pdf");

Lancer signifie que je peux supposer des invariants beaucoup plus forts dans ce cas, et c'est donc une bonne chose.

Étant donné que l'opération de sortie ne change pas l'état de CheeseSales le lancer ne renforcerait pas autant les invariants. Dans ce cas, il est préférable d'utiliser un objet d'aide pour imprimer le graphique :

ChooseSales sales("cheesesales.txt");
PdfStream chart("piechart.pdf");
chart << sales.asPieChart();

( PdfStream pourrait juste être std::ofstream mais vous aimeriez peut-être fournir d'autres fonctionnalités).

Si l'opération échoue, elle peut mettre la chart dans un état d'erreur, ce qui correspondrait à la façon dont les iostreams fonctionnent généralement.

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