如果您打开文件然后将其关闭。如果您尝试关闭已经关闭的文件,为什么程序会编译?
例如
ifstream inFile;
inFile.open("filename");
inFile.close();
inFile.close();
为什么编译器不能识别您已经关闭了文件?
答案 0 :(得分:3)
为什么编译器不能识别您已经关闭了文件?
这些语句在语法上是正确的,因此编译器不会抱怨。
理论上第二个close()
调用可能在运行时失败,但由于它是一个幂等操作,它不会。
注释
当流对象超出范围并且通常不直接调用时,basic_fstream的析构函数调用此函数。
甚至必须以同等方式实施。
答案 1 :(得分:2)
标准清楚地明确指出如果你在未打开的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
具有未定义的行为,编译器也不会拒绝这一点。你的工作就是不写代码,而不是编译器的工作来抓住代码。
答案 2 :(得分:1)
此类代码可能产生的错误类型是运行时异常。编译器不关心这些事情。相反,它会将您的代码解析为目标文件,以便进行后续链接。要生成这些目标文件,您的代码只需要在语法上正确并且与您选择的语言格式正确。
因此,只有在将目标文件链接到库或可执行文件然后执行之后,才会发生运行时异常。
也许答案是:编译器不知道或不关心代码的运行时行为,而你提到的错误类型是运行时错误。