ฉันต้องปิด 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

NO

นี่คือสิ่งที่ RAII มีไว้เพื่อให้ผู้ทำลายล้างทำงานได้ ไม่มีอันตรายใด ๆ ในการปิดด้วยตนเอง แต่ไม่ใช่วิธี C ++ แต่เป็นการเขียนโปรแกรมใน C กับคลาส

หากคุณต้องการปิดไฟล์ก่อนสิ้นสุดฟังก์ชั่นคุณสามารถใช้ขอบเขตที่ซ้อนกันได้เสมอ

ในมาตรฐาน (27.8.1.5 แม่แบบคลาส basic_ifstream) ifstreamจะต้องมีการดำเนินการกับbasic_filebufสมาชิกที่ถือจัดการไฟล์จริง จะจัดขึ้นในฐานะสมาชิกคนเพื่อที่ว่าเมื่อวัตถุ ifstream การทำลายก็ยังเรียก destructor basic_filebufบน และจากมาตรฐาน (27.8.1.2) destructor นั้นปิดไฟล์:

virtual ˜basic_filebuf();

เอฟเฟค:basic_filebuf<charT,traits>ทำลายวัตถุของคลาส โทรclose().


4
+1 ผมไม่ทราบว่า RAII จับที่ ... ฉันคิดว่าคุณได้เรียนรู้สิ่งใหม่ทุกวัน
TStamper

21
การใช้ขอบเขตที่ซ้อนกันเพื่อปิดไฟล์นั้นเป็นสิ่งปลอมปนอย่างสมบูรณ์ - ถ้าคุณต้องการปิดมันให้โทรปิด () ที่มัน

3
แม้ว่าคุณจะสามารถโต้แย้งได้ว่าการ จำกัด อายุการใช้งานของวัตถุในขอบเขตที่จำเป็นหมายความว่าคุณจะไม่เข้าถึง ifstream ที่ปิดโดยไม่ตั้งใจ แต่นั่นก็เป็นการประดิษฐ์
Eclipse

9
ในขอบเขต C ++ ที่ซ้อนกันแทบไม่จำเป็นเลย พวกเขามีทุกสิ่งที่เกี่ยวข้องกับพฤติกรรมของรหัสโดยเฉพาะอย่างยิ่งเมื่อมีบางอย่างเกิดขึ้น หากผู้ดูแลในอนาคตลบพวกเขาเขาไม่รู้จัก C ++ เป็นอย่างดี
Elliot Cameron

2
บางครั้งคุณต้องโทรหาclose()ด้วยตนเองเพื่อจัดการข้อผิดพลาด
ks1322

71

คุณต้องการปิดไฟล์หรือไม่?
NO

คุณควรปิดไฟล์หรือไม่
ขึ้นอยู่กับ

คุณสนใจเกี่ยวกับเงื่อนไขข้อผิดพลาดที่อาจเกิดขึ้นหากไฟล์ไม่สามารถปิดได้อย่างถูกต้องหรือไม่ โปรดจำไว้ว่าการปิดการโทรsetstate(failbit)หากล้มเหลว ตัวทำลายจะโทรclose()หาคุณโดยอัตโนมัติเนื่องจากRAIIแต่จะไม่ปล่อยให้คุณทดสอบบิตล้มเหลวเนื่องจากวัตถุไม่มีอยู่อีกต่อไป


14

ฉันเห็นด้วยกับ @Martin หากคุณเขียนไปยังไฟล์ข้อมูลอาจยังคงอยู่ในบัฟเฟอร์และอาจไม่ถูกเขียนลงในไฟล์จนกว่าclose()จะมีการเรียกใช้ คุณไม่ทราบว่ามีข้อผิดพลาดหรือไม่ การไม่รายงานข้อผิดพลาดให้กับผู้ใช้ถือเป็นการปฏิบัติที่เลวร้ายมาก


5

ไม่สิ่งนี้ทำโดยอัตโนมัติโดยifstreamdestructor เหตุผลเดียวที่คุณควรเรียกมันด้วยตนเองเป็นเพราะfstreamอินสแตนซ์มีขอบเขตขนาดใหญ่ตัวอย่างเช่นถ้ามันเป็นตัวแปรสมาชิกของอินสแตนซ์คลาสที่มีชีวิตที่ยาวนาน


4
อีกเหตุผลหนึ่งก็คือตรวจสอบข้อผิดพลาดในการปิดไฟล์และเพื่อป้องกันการทำลาย destructor หากข้อยกเว้นนั้นได้รับอนุญาตกับสตรีม
Daniel Langr

4

คุณสามารถอนุญาตให้ destructor ทำงานได้ แต่เช่นเดียวกับวัตถุ 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);
}

ไม่ นี่เป็นกรณีที่ไม่ค่อยเกิดขึ้นเมื่อกระบวนการออกมาโดยฉับพลัน กระบวนการขัดข้องอาจทำเช่นเดียวกัน

โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.