Tôi có cần phải tự đóng một ifux không?


201

Tôi có cần gọi thủ công close()khi tôi sử dụngstd::ifstream không?

Ví dụ: trong mã:

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

Tôi có cần gọi file.close()thủ công không? Không nên ifstreamsử dụng RAII để đóng tệp?

Câu trả lời:


251

KHÔNG

Đây là những gì RAII dành cho, hãy để kẻ hủy diệt thực hiện công việc của nó. Không có hại khi đóng nó bằng tay, nhưng đó không phải là cách của C ++, đó là lập trình trong C với các lớp.

Nếu bạn muốn đóng tệp trước khi kết thúc hàm, bạn luôn có thể sử dụng phạm vi lồng nhau.

Trong tiêu chuẩn (mẫu lớp 27.8.1.5 basic_ifstream), ifstreamsẽ được triển khai với một basic_filebufthành viên đang xử lý tệp thực tế. Nó được tổ chức như một thành viên để khi một đối tượng ifstream phá hủy, nó cũng gọi hàm hủy trên basic_filebuf. Và từ tiêu chuẩn (27.8.1.2), hàm hủy đó đóng tệp:

virtual ˜basic_filebuf();

Tác dụng: Phá hủy một đối tượng của lớp basic_filebuf<charT,traits>. Các cuộc gọi close().


4
+1 Tôi không biết rằng RAII xử lý việc đó ... Tôi đoán bạn học được điều gì đó mới mỗi ngày
TStamper

21
Sử dụng một phạm vi lồng nhau chỉ để đóng tệp là hoàn toàn nhân tạo - nếu bạn muốn đóng nó, hãy gọi close () trên nó.

3
Mặc dù, bạn có thể lập luận rằng việc giới hạn thời gian tồn tại của đối tượng trong phạm vi cần thiết có nghĩa là bạn sẽ không vô tình truy cập vào một luồng đóng. Nhưng đó là một chút giả tạo.
Nhật thực

9
Trong phạm vi lồng nhau C ++ hầu như không bao giờ không cần thiết. Họ có mọi thứ để làm với hành vi của mã, đặc biệt là khi một cái gì đó ném. Nếu một người duy trì trong tương lai loại bỏ chúng, anh ta không biết rõ về C ++.
Elliot Cameron

2
Đôi khi bạn cần phải gọi close()thủ công để xử lý lỗi.
ks1322

71

Bạn có cần phải đóng tập tin?
KHÔNG

Bạn có nên đóng tập tin?
Phụ thuộc.

Bạn có quan tâm đến các điều kiện lỗi có thể xảy ra nếu tệp không đóng đúng không? Hãy nhớ rằng các cuộc gọi gần setstate(failbit)nếu nó thất bại. Hàm hủy sẽ close()tự động gọi cho bạn vì RAII nhưng sẽ không để lại cho bạn cách kiểm tra bit fail vì đối tượng không còn tồn tại.


14

Tôi đồng ý với @Martin. Nếu bạn ghi vào tệp, dữ liệu có thể vẫn đang nằm trên bộ đệm và có thể không được ghi vào tệp cho đến khi close()được gọi. Không làm thủ công, bạn không biết có lỗi hay không. Không báo cáo lỗi cho người dùng là một thực tế rất xấu.


5

Không, điều này được thực hiện tự động bởi các hàm ifstreamhủy. Lý do duy nhất bạn nên gọi nó bằng tay, là vì fstreamthể hiện có phạm vi lớn, ví dụ nếu nó là biến thành viên của một thể hiện lớp sống lâu.


4
Một lý do khác có thể là để kiểm tra lỗi đóng tệp và để tránh ném hủy, nếu ngoại lệ được cho phép với luồng.
Daniel Langr

4

Bạn có thể cho phép hàm hủy thực hiện công việc của nó. Nhưng cũng giống như bất kỳ đối tượng RAII nào, có thể đôi khi việc gọi đóng bằng tay có thể tạo ra sự khác biệt. Ví dụ:

#include <fstream>

using std::ofstream;

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

ghi nội dung tập tin. Nhưng:

#include <stdlib.h>

#include <fstream>

using std::ofstream;

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

không. Đây là những trường hợp hiếm hoi khi một quá trình đột nhiên thoát ra. Một quá trình sụp đổ có thể làm tương tự.

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.