Чи потрібно вручну закривати 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, може бути час, коли виклик закриття вручну може змінити значення. Наприклад:

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

не робить. Це рідкісні випадки, коли процес раптово закінчується. Процес краху може зробити подібне.

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.