¿Necesito cerrar manualmente un ifstream?

201

¿Debo llamar manualmente close()cuando uso un std::ifstream?

Por ejemplo, en el 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");
}

¿Necesito llamar file.close()manualmente? ¿No debería ifstreamhacer uso de RAII para cerrar archivos?

Edison Gustavo Muenz
fuente

Respuestas:

251

NO

Para eso es RAII, deje que el destructor haga su trabajo. No hay ningún daño en cerrarlo manualmente, pero no es la forma de C ++, es la programación en C con clases.

Si desea cerrar el archivo antes del final de una función, siempre puede usar un ámbito anidado.

En el estándar (27.8.1.5 Plantilla de clase basic_ifstream), ifstreamdebe implementarse con un basic_filebufmiembro que tenga el identificador de archivo real. Se mantiene como un miembro para que cuando un objeto ifstream se destruya, también active el destructor basic_filebuf. Y desde el estándar (27.8.1.2), ese destructor cierra el archivo:

virtual ˜basic_filebuf();

Efectos: destruye un objeto de clase basic_filebuf<charT,traits>. Llamadas close().

Eclipse
fuente
44
+1 No sabía que RAII maneja eso ... Supongo que aprendes algo nuevo todos los días
TStamper
21
Usar un ámbito anidado solo para cerrar el archivo es completamente artificial; si quiere cerrarlo, llame a close () en él.
3
Sin embargo, es posible que pueda argumentar que restringir la vida útil del objeto al alcance necesario significa que no accederá accidentalmente a un ifstream cerrado. Pero eso es un poco artificial.
Eclipse
9
En C ++, los ámbitos anidados casi nunca son innecesarios. Tienen todo que ver con el comportamiento del código, especialmente cuando algo arroja. Si un futuro mantenedor los elimina, no conoce muy bien C ++.
Elliot Cameron
2
A veces es necesario llamar close()manualmente para el manejo de errores.
ks1322
71

¿Necesitas cerrar el archivo?
NO

¿Deberías cerrar el archivo?
Depende

¿Le preocupan las posibles condiciones de error que podrían ocurrir si el archivo no se cierra correctamente? Recuerde que cierra las llamadas setstate(failbit)si falla. El destructor lo llamará close()automáticamente debido a RAII pero no le dejará una forma de probar el bit de falla ya que el objeto ya no existe.

Martin York
fuente
14

Estoy de acuerdo con @Martin. Si escribe en el archivo, es posible que los datos permanezcan en un búfer y no se escriban en el archivo hasta que close()se llame. Sin hacerlo manualmente, no tiene idea de si hubo un error o no. No informar errores a un usuario es una muy mala práctica.

Mark Edwards
fuente
5

No, esto lo hace automáticamente el ifstreamdestructor. La única razón por la que debe llamarlo manualmente es porque la fstreaminstancia tiene un gran alcance, por ejemplo, si es una variable miembro de una instancia de clase de larga vida.

Dimitri C.
fuente
44
Otra razón podría ser verificar los errores de cierre de archivos y evitar el lanzamiento del destructor, si se permiten excepciones con la secuencia.
Daniel Langr
4

Puede permitir que el destructor haga su trabajo. Pero al igual que cualquier objeto RAII, puede haber ocasiones en que las llamadas cerradas manualmente puedan marcar la diferencia. Por ejemplo:

#include <fstream>

using std::ofstream;

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

escribe el contenido del archivo. Pero:

#include <stdlib.h>

#include <fstream>

using std::ofstream;

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

no lo hace Estos son casos raros en los que un proceso sale repentinamente. Un proceso de bloqueo podría hacer algo similar.

ericcurtin
fuente