web-dev-qa-db-fra.com

Est-ce une mauvaise pratique de lire le gros fichier dans le constructeur?

Donc, j'essaie de créer une implémentation de la structure de données Trie de langue anglaise en C++. J'ai créé un Trie et TrieNode classe. La classe TrieNode prend son constructeur un vector<string> C'est une liste de mots pour construire la trie de.

Ma solution pour obtenir ce vector<string> était d'utiliser une classe EnglishWordsListGenerator, qui, dans son constructeur, prend une chaîne de nom de fichier d'un fichier qui contient probablement une liste de mots anglais valides. (Le toujours populaire enable1.txt déposer).

Je suis nouveau à C++, donc je ne sais pas s'il est considéré comme une bonne pratique ou non de lire le fichier directement à partir du constructeur lors de l'initialisation de l'objet. Après tout, que si l'opération échoue? D'autre part, je sais que Bjarne pousse fortement pour Raii. Quelle est la bonne chose à faire ici?

7
Bassinator

Lorsque vous voyez une classe avec une signature de constructeur comme

 EnglishWordsListGenerator(const std::string &wordFileName)

Je pense qu'il est assez évident que ce constructeur lira le fichier donné (et aussi besoin de temps), et il ne devrait pas être difficile de comprendre que l'appelant doit prendre soin des exceptions possibles à partir de ceci (car le fichier IO peut échouer). Donc, malgré quelles autres réponses disent, cette conception est ok.

Ne vous méprenez pas, à l'avenir, vous risquez d'obtenir des exigences où cette conception pourrait ne pas être suffisante, mais aussi longtemps que cette interface et ce comportement simples sont tous vos besoins de votre programme, j'en collerais au KISS et des principes yagni et évitez de surcharger des choses en fournissant une méthode d'initialisation distincte "juste au cas où".

16
Doc Brown

Ce n'est pas une bonne pratique de charger un objet d'un fichier dans le constructeur.

Au-delà des bons arguments C++ dans les autres réponses, j'ajouterais un principe de code de nettoyage: ne fonction ne doit faire qu'une seule chose. OK, le constructeur n'est pas une fonction normale, mais le principe s'applique toujours.

Je suggère ce qui suit:

  • gardez le Trie aussi général que possible de viser la réutilisation. Il y a beaucoup d'autres applications qui pourraient l'utiliser.
  • gardez-le indépendamment de votre façon de le nourrir: idéalement. Différente application pourrait utiliser différentes approches, par exemple pour l'alimenter à partir d'un string ou d'un istream. Après tout, les futures versions de votre application pourraient interroger les mots d'une base de données avec différentes langues.
  • utilisez un modèle de conception du constructeur , pour assembler les morceaux du processus de construction. Le constructeur chargerait ensuite la trie à partir d'une source, en utilisant une sorte d'approche générale (par exemple, créez la trie, ouvrez la source, itérale via des données source et l'insérer dans la trie, une fois que cela se produise, renvoyez la trie). Vous pouvez ensuite créer un constructeur de béton pour le chargement d'un fichier et opter facilement pour d'autres alternatives.
5
Christophe

Je ne pense pas que je connais un fichier dans le constructeur pour quelques raisons:

  1. il ralentira considérablement la création d'objets et potentiellement le démarrage de votre programme.
  2. comme vous l'avez mentionné, il existe des options limitées pour la manipulation des erreurs. Il vous faudrait soit mettre l'ensemble du programme dans un essai ... Catch Block ou définir une sorte de drapeau si quelque chose ne va pas.
  3. et si vous avez besoin de le lire plus d'une fois? Vous devriez avoir un duplicata du code ou diviser le code sur une fonction des appels de constructeur, auquel cas le faisait simplement une fois que l'objet est créé de toute façon.

Je suis sûr qu'il y a une autre raison, ce sont les premiers qui me sont venus à mon esprit. Si c'est un petit fichier et que vous ne le lisez que la fois, vous allez probablement bien.

1
bluegreen