使用 fstream 关闭文件

Closing files using fstream

本文关键字:文件 fstream 使用      更新时间:2023-10-16

如果您打开一个文件,然后关闭它。如果您尝试关闭已经关闭的文件,为什么程序会编译?

例如

ifstream inFile;
inFile.open("filename");
inFile.close();
inFile.close();

为什么编译器无法识别您已经关闭了文件?

为什么编译器无法识别您已经关闭了文件?

这些语句在语法上是正确的,因此编译器不会抱怨。

从理论上讲,第二个close()调用可能会在运行时失败,但由于它是幂等操作,因此不会失败。

从参考文档中可以看出:

笔记

当流对象超出范围且通常不直接调用时,basic_fstream 的析构函数将调用此函数。

它甚至必须以幂等方式实现。

该标准明确规定了如果您在未打开的 fstreambuf 上调用 close()会发生什么(没有效果,即它什么都不做),因此它在运行时不是错误,因此编译器拒绝编译此类代码是完全错误的。

在任何情况下,编译器都不会在C++中检查类似的东西。让我们想象一个C++像你期望的那样工作的世界。如果你有这样的函数:

void close(std::ifstream& f);

它恰好实现(在其他某个文件中)为:

void close(std::ifstream& f) { f.close(); }

您将代码更改为:

ifstream inFile;
inFile.open("filename");
close(inFile);
inFile.close();

然后它会编译正常,因为编译器无法"看到"第一次调用关闭文件。但是,如果close(std::fstream&)函数是内联的,编译器现在是否应该拒绝它?或者只有在单个函数中直接调用时才会出现错误?你想象的世界很难处理,也很难指定。这将使代码非常脆弱和上下文相关,并使重构变得困难。

C++不是那样工作的,这是一件好事。

你想象的世界还需要编译器"理解"inFile.close()的含义。就编译器而言,它只是执行一系列操作,最终导致一些调用,如 fclose(fp)close(fd) ,但这将嵌套在几个级别的函数调用中,可能不是内联的。即使它们都是内联的,编译器也不会"理解"每个操作的含义和效果,它只是编译你写的内容并调用你告诉它调用的函数。你如何期望它"知道"所有这些代码的实际含义

举一个非常简单的方法,编译器确实理解每个操作的含义:

int i = 1;
int* p = &i;
int j = *p;
p = nullptr;
int k = *p;

编译器甚至不会拒绝这一点,即使第二个*p具有未定义的行为。你的工作是不编写代码,而不是编译器的工作来捕获它。

此类代码可能产生的错误类型是运行时异常。编译器不关心这些事情。相反,它会将您的代码解析为对象文件以供后续链接。若要生成这些对象文件,代码只需在语法上正确且相对于所选语言的格式正确。

因此,只有在将目标文件链接到库或可执行文件中然后执行之后,才会发生运行时异常。

也许答案是:编译器不知道或不关心代码的运行时行为,并且您提到的错误类型是运行时错误。