Dois-je fermer manuellement un ifstream?

201

Dois-je appeler manuellement close()lorsque j'utilise un std::ifstream?

Par exemple, dans le code:

std::string readContentsOfFile(std::string fileName) {

  std::ifstream file(fileName.c_str());

  if (file.good()) {
      std::stringstream buffer;
      buffer << file.rdbuf();
      file.close();

      return buffer.str();
  }
  throw std::runtime_exception("file not found");
}

Dois-je appeler file.close()manuellement? Ne devrait pas ifstreamutiliser RAII pour fermer des fichiers?

Edison Gustavo Muenz
la source

Réponses:

251

NON

C'est à cela que sert RAII, laissez le destructeur faire son travail. Il n'y a aucun mal à le fermer manuellement, mais ce n'est pas la manière C ++, c'est la programmation en C avec des classes.

Si vous souhaitez fermer le fichier avant la fin d'une fonction, vous pouvez toujours utiliser une étendue imbriquée.

Dans la norme (modèle de classe 27.8.1.5 basic_ifstream), ifstreamdoit être implémenté avec un basic_filebufmembre détenant le handle de fichier réel. Il est conservé en tant que membre de sorte que lorsqu'un objet ifstream se détruit, il appelle également le destructeur basic_filebuf. Et à partir de la norme (27.8.1.2), ce destructeur ferme le fichier:

virtual ˜basic_filebuf();

Effets: détruit un objet de classe basic_filebuf<charT,traits>. Appels close().

Éclipse
la source
4
+1 Je ne savais pas que RAII gère ça ... Je suppose que vous apprenez quelque chose de nouveau tous les jours
TStamper
21
Utiliser une portée imbriquée juste pour fermer le fichier est complètement artificiel - si vous voulez le fermer, appelez close () dessus.
3
Cependant, vous pourrez peut-être affirmer que restreindre la durée de vie de l'objet à la portée nécessaire signifie que vous n'accéderez pas accidentellement à un ifstream fermé. Mais c'est un peu artificiel.
Eclipse
9
En C ++, les étendues imbriquées ne sont presque jamais inutiles. Ils ont tout à voir avec le comportement du code, surtout quand quelque chose se déclenche. Si un futur mainteneur les supprime, il ne connaît pas très bien le C ++.
Elliot Cameron
2
Parfois, vous devez appeler close()manuellement pour la gestion des erreurs.
ks1322
71

Avez-vous besoin de fermer le fichier?
NON

Devez-vous fermer le fichier?
Dépend.

Vous souciez-vous des conditions d'erreur possibles qui pourraient se produire si le fichier ne se ferme pas correctement? N'oubliez pas que fermer les appels en setstate(failbit)cas d'échec. Le destructeur close()vous appellera automatiquement à cause de RAII mais ne vous laissera pas un moyen de tester le bit d'échec car l'objet n'existe plus.

Martin York
la source
14

Je suis d'accord avec @Martin. Si vous écrivez dans le fichier, les données peuvent toujours être stockées dans un tampon et peuvent ne pas être écrites dans le fichier avant l' close()appel. Sans le faire manuellement, vous n'avez aucune idée s'il y a eu une erreur ou non. Ne pas signaler d'erreurs à un utilisateur est une très mauvaise pratique.

Mark Edwards
la source
5

Non, cela se fait automatiquement par le ifstreamdestructeur. La seule raison pour laquelle vous devez l'appeler manuellement, c'est parce que l' fstreaminstance a une grande portée, par exemple s'il s'agit d'une variable membre d'une instance de classe longue durée.

Dimitri C.
la source
4
Une autre raison pourrait être de vérifier les erreurs de fermeture de fichiers et d'empêcher le lancement du destructeur, si des exceptions sont autorisées avec le flux.
Daniel Langr
4

Vous pouvez permettre au destructeur de faire son travail. Mais tout comme n'importe quel objet RAII, il peut arriver que l'appel manuel à close fasse une différence. Par exemple:

#include <fstream>

using std::ofstream;

int main() {
  ofstream ofs("hello.txt");
  ofs << "Hello world\n";
  return 0;
}

écrit le contenu du fichier. Mais:

#include <stdlib.h>

#include <fstream>

using std::ofstream;

int main() {
  ofstream ofs("hello.txt");
  ofs << "Hello world\n";
  exit(0);
}

non. Ce sont de rares cas où un processus se termine soudainement. Un processus de plantage pourrait faire de même.

ericcurtin
la source