我需要手动关闭ifstream吗?

257

当我使用 std::ifstream 时,是否需要手动调用 close() 呢?

例如,在以下代码中:

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

我需要手动调用 file.close() 吗?ifstream 不应该使用RAII关闭文件吗?

4个回答

306

RAII的作用就是让析构函数完成工作。 手动关闭文件不会有任何问题,但这不是C++的方式,这是使用类编程的C。

如果想在函数结束前关闭文件,可始终使用嵌套作用域。

根据标准(27.8.1.5类模板basic_ifstream),ifstream应使用一个保存实际文件句柄的basic_filebuf成员实现。 它被保存为成员,以便当ifstream对象析构时,它也调用basic_filebuf的析构函数。 根据标准(27.8.1.2), 该析构函数关闭文件:

virtual ˜basic_filebuf();

效果:销毁basic_filebuf<charT,traits>类的对象。 调用close()


8
+1 我不知道 RAII 处理那个...我猜每天都会学到新东西。 - TStamper
38
仅仅为了关闭文件而使用嵌套的作用域是完全人为的 - 如果你想要关闭它,就调用 close() 方法。 - anon
5
尽管你可能会认为将对象的生命周期限制在必要的范围内意味着你不会意外访问已关闭的ifstream,但这有点牵强。 - Eclipse
13
在C++中,嵌套作用域几乎从来不是不必要的。它们与代码行为有密切关系,尤其是当某些内容抛出异常时。如果未来的维护者移除了它们,那么他并不是很了解C++。 - Elliot Cameron
4
有时候你需要手动调用 close() 来处理错误。 - ks1322
显示剩余9条评论

82

你需要关闭文件吗?
不需要。

你应该关闭文件吗?
这要看情况。

你在意文件没有正确关闭可能导致的错误情况吗?请记住,如果关闭失败,调用close()setstate(failbit)。由于RAII的原因,析构函数会自动为您调用close(),但不会留下测试失败位的方法,因为对象已经不存在了。


我认为值得一提的是,您可以使用“exceptions”函数将此类错误转换为异常抛出,而不是进行手动测试。Eric Lippert有一篇有趣的博客文章,其中提到文件IO是异步情况下异常确实更好的选择的一个例子。也就是说,挂载的磁盘可能在任何时候被移除,而不仅仅是在程序检查其是否存在时。 - Pharap

7

您可以让析构函数完成它的工作。但就像任何RAII对象一样,有时手动调用close可能会产生差异。例如:

#include <fstream>

using std::ofstream;

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

写入文件内容。但是:
#include <stdlib.h>

#include <fstream>

using std::ofstream;

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

这种情况很少见,通常是一个进程突然退出。崩溃的进程可能会有类似的情况。


6
不,这是由ifstream析构函数自动完成的。您应该手动调用它的唯一原因是fstream实例的作用域很大,例如它是一个长期存在的类实例的成员变量。

6
另一个原因可能是为了检查文件关闭错误并防止在流允许异常的情况下抛出析构函数。 - Daniel Langr

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接