Нужно ли вручную закрывать ifstream?

201

Нужно ли мне вручную звонить, close()когда я использую std::ifstream?

Например, в коде:

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 для закрытия файлов?

Эдисон Густаво Муенц
источник

Ответы:

251

НЕТ

Для этого и нужен 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().

Затмение
источник
4
+1 Я не знал, что RAII справится с этим ... Я думаю, ты каждый день узнаешь что-то новое
TStamper
21
Использование вложенной области видимости только для того, чтобы закрыть файл, является полностью искусственным - если вы хотите закрыть его, вызовите для него close ().
3
Хотя вы можете утверждать, что ограничение времени жизни объекта до необходимой области означает, что вы не будете случайно получать доступ к закрытому потоку if. Но это немного надумано.
Затмение
9
В C ++ вложенные области практически никогда не нужны. Они имеют все, что связано с поведением кода, особенно когда что-то выбрасывается. Если будущий сопровождающий удалит их, он не очень хорошо знает C ++.
Эллиот Кэмерон
2
Иногда вам нужно позвонить close()вручную для обработки ошибок.
ks1322
71

Вам нужно закрыть файл?
НЕТ

Вы должны закрыть файл?
Смотря как.

Вы заботитесь о возможных условиях ошибки, которые могут возникнуть, если файл не закрывается правильно? Помните, что закрыть звонки, setstate(failbit)если это не удается Деструктор будет вызывать close()вас автоматически из-за RAII, но не оставит вам способа проверить бит сбоя, поскольку объект больше не существует.

Мартин Йорк
источник
14

Я согласен с @Martin. Если вы записываете в файл, данные могут все еще находиться в буфере и могут не записываться в файл, пока не close()будет вызван. Не делая этого вручную, вы не представляете, произошла ошибка или нет. Не сообщать пользователю об ошибках - очень плохая практика.

Марк Эдвардс
источник
5

Нет, это делается автоматически ifstreamдеструктором. Единственная причина, по которой вы должны вызывать его вручную, заключается в том, что fstreamэкземпляр имеет большую область видимости, например, если это переменная-член экземпляра класса с длительным сроком службы.

Димитрий С.
источник
4
Другой причиной может быть проверка ошибок закрытия файла и предотвращение создания деструктора, если в потоке разрешены исключения.
Даниэль Лангр
4

Вы можете позволить деструктору делать свою работу. Но, как и в случае любого объекта 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);
}

не делает. Это редкие случаи, когда процесс внезапно завершается. Процесс сбоя может сделать то же самое.

ericcurtin
источник