Preciso fechar manualmente um ifstream?

201

Preciso ligar manualmente close() quando uso um std::ifstream?

Por exemplo, no código:

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");
}

Preciso ligar file.close()manualmente? Não deve ifstreamusar o RAII para fechar arquivos?

Edison Gustavo Muenz
fonte

Respostas:

251

NÃO

É para isso que serve a RAII, deixe o destruidor fazer seu trabalho. Não há mal em fechá-lo manualmente, mas não é o modo C ++, é programar em C com classes.

Se você deseja fechar o arquivo antes do final de uma função, sempre pode usar um escopo aninhado.

No padrão (27.8.1.5 Class template basic_ifstream), ifstreamdeve ser implementado com um basic_filebufmembro segurando o identificador de arquivo real. Ele é mantido como um membro para que, quando um objeto ifstream destrua, ele também chame o destruidor basic_filebuf. E do padrão (27.8.1.2), esse destruidor fecha o arquivo:

virtual ˜basic_filebuf();

Efeitos: Destrói um objeto de classe basic_filebuf<charT,traits>. Chamadas close().

Eclipse
fonte
4
+1 Eu não sabia que lida com RAII que ... Eu acho que você aprender algo novo todos os dias
TStamper
21
Usar um escopo aninhado apenas para fechar o arquivo é completamente artificial - se você quiser fechá-lo, chame close ().
3
Embora você possa argumentar que restringir a vida útil do objeto ao escopo necessário significa que você não acessará acidentalmente um fluxo de fluxo fechado. Mas isso é um pouco artificial.
Eclipse
9
No C ++, os escopos aninhados quase nunca são desnecessários. Eles têm tudo a ver com o comportamento do código, especialmente quando algo é lançado. Se um futuro mantenedor os remove, ele não conhece muito bem o C ++.
Elliot Cameron
2
Às vezes, você precisa ligar close()manualmente para tratamento de erros.
precisa saber é o seguinte
71

Você precisa fechar o arquivo?
NÃO

Você deve fechar o arquivo?
Depende.

Você se preocupa com as possíveis condições de erro que podem ocorrer se o arquivo não fechar corretamente? Lembre-se de que fechar chamadas setstate(failbit)se falhar. O destruidor chamará close()você automaticamente por causa do RAII, mas não permitirá que você teste o bit de falha, pois o objeto não existe mais.

Martin York
fonte
14

Eu concordo com @Martin. Se você gravar no arquivo, os dados ainda poderão estar em um buffer e poderão não ser gravados no arquivo até que close()sejam chamados. Sem fazer isso manualmente, você não tem idéia se houve um erro ou não. Não relatar erros para um usuário é uma prática muito ruim.

Mark Edwards
fonte
5

Não, isso é feito automaticamente pelo ifstreamdestruidor. O único motivo pelo qual você deve chamá-lo manualmente é porque a fstreaminstância tem um grande escopo, por exemplo, se é uma variável membro de uma instância de classe longa vida.

Dimitri C.
fonte
4
Outro motivo pode ser o de verificar erros de fechamento de arquivo e impedir o lançamento de destruidor, se exceções forem permitidas no fluxo.
11117 Daniel Langr
4

Você pode permitir que o destruidor faça seu trabalho. Mas, como qualquer objeto RAII, pode haver momentos em que fechar manualmente manualmente pode fazer a diferença. Por exemplo:

#include <fstream>

using std::ofstream;

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

escreve o conteúdo do arquivo. Mas:

#include <stdlib.h>

#include <fstream>

using std::ofstream;

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

não. São casos raros em que um processo sai repentinamente. Um processo de falha pode fazer o mesmo.

ericcurtina
fonte