使用 fstream 关闭文件
Closing files using fstream
如果您打开一个文件然后关闭它。如果您尝试关闭一个已经关闭的文件,为什么程序会编译?
例如
ifstream inFile;
inFile.open("filename");
inFile.close();
inFile.close();
为什么编译器无法识别您已经关闭的文件?
Why doesn't the compiler recognize that you already closed the file?
这些语句在语法上是正确的,所以编译器不会报错。
理论上第二个 close()
调用可能会在运行时失败,但由于它是幂等操作,所以不会。
从reference documentation可以看出:
Notes
This function is called by the destructor of basic_fstream when the stream object goes out of scope and is not usually invoked directly.
甚至必须幂等地实现。
这种代码可能产生的错误类型是运行时异常。编译器不关心这些事情。相反,它将您的代码解析为目标文件以供后续链接。要生成这些目标文件,您的代码只需要针对您选择的语言在句法上正确且格式正确即可。
所以只有当你的目标文件链接到一个库或可执行文件然后执行后,才会发生运行时异常。
也许答案是:编译器不知道或不关心您代码的运行时行为,您提到的错误类型是运行时错误。
该标准清楚地指定了如果您在未打开的 fstreambuf 上调用 close()
会发生什么情况(没有效果,即它什么都不做),所以在 运行-time,所以编译器拒绝编译这样的代码是完全错误的。
在任何情况下,编译器都不会检查 C++ 中的类似内容。让我们想象一个 C++ 像您期望的那样工作的世界。如果你有这样的功能:
void close(std::ifstream& f);
恰好(在其他文件中)实现为:
void close(std::ifstream& f) { f.close(); }
然后您将代码更改为:
ifstream inFile;
inFile.open("filename");
close(inFile);
inFile.close();
然后它会编译 OK,因为编译器不能 "see" 第一次调用关闭文件。但是如果 close(std::fstream&)
函数是内联的,编译器现在会拒绝它吗?或者只有在单个函数中直接调用才会出错?你想象的世界很难处理,也很难具体说明。这会使代码变得非常脆弱和上下文敏感,并使重构变得困难。
C++ 不是这样工作的,这是一件好事。
您想象的世界还需要编译器 "understand" inFile.close()
的意思。就编译器而言,它只是执行一系列操作,最终导致一些调用,如 fclose(fp)
或 close(fd)
,但它将嵌套在函数调用的多个级别中,可能不是内联的。即使它们都是内联的,编译器也不会 "understand" 每个操作的含义和效果,它只是编译您编写的内容并调用您告诉它调用的函数。您如何期望它 "know" 所有这些代码实际上 意味着 ?
编译器确实理解了每个操作的含义:
int i = 1;
int* p = &i;
int j = *p;
p = nullptr;
int k = *p;
编译器甚至不会拒绝这个,即使第二个 *p
有未定义的行为。不编写该代码是你的工作,而不是编译器的工作来捕获它。
如果您打开一个文件然后关闭它。如果您尝试关闭一个已经关闭的文件,为什么程序会编译?
例如
ifstream inFile;
inFile.open("filename");
inFile.close();
inFile.close();
为什么编译器无法识别您已经关闭的文件?
Why doesn't the compiler recognize that you already closed the file?
这些语句在语法上是正确的,所以编译器不会报错。
理论上第二个 close()
调用可能会在运行时失败,但由于它是幂等操作,所以不会。
从reference documentation可以看出:
Notes
This function is called by the destructor of basic_fstream when the stream object goes out of scope and is not usually invoked directly.
甚至必须幂等地实现。
这种代码可能产生的错误类型是运行时异常。编译器不关心这些事情。相反,它将您的代码解析为目标文件以供后续链接。要生成这些目标文件,您的代码只需要针对您选择的语言在句法上正确且格式正确即可。
所以只有当你的目标文件链接到一个库或可执行文件然后执行后,才会发生运行时异常。
也许答案是:编译器不知道或不关心您代码的运行时行为,您提到的错误类型是运行时错误。
该标准清楚地指定了如果您在未打开的 fstreambuf 上调用 close()
会发生什么情况(没有效果,即它什么都不做),所以在 运行-time,所以编译器拒绝编译这样的代码是完全错误的。
在任何情况下,编译器都不会检查 C++ 中的类似内容。让我们想象一个 C++ 像您期望的那样工作的世界。如果你有这样的功能:
void close(std::ifstream& f);
恰好(在其他文件中)实现为:
void close(std::ifstream& f) { f.close(); }
然后您将代码更改为:
ifstream inFile;
inFile.open("filename");
close(inFile);
inFile.close();
然后它会编译 OK,因为编译器不能 "see" 第一次调用关闭文件。但是如果 close(std::fstream&)
函数是内联的,编译器现在会拒绝它吗?或者只有在单个函数中直接调用才会出错?你想象的世界很难处理,也很难具体说明。这会使代码变得非常脆弱和上下文敏感,并使重构变得困难。
C++ 不是这样工作的,这是一件好事。
您想象的世界还需要编译器 "understand" inFile.close()
的意思。就编译器而言,它只是执行一系列操作,最终导致一些调用,如 fclose(fp)
或 close(fd)
,但它将嵌套在函数调用的多个级别中,可能不是内联的。即使它们都是内联的,编译器也不会 "understand" 每个操作的含义和效果,它只是编译您编写的内容并调用您告诉它调用的函数。您如何期望它 "know" 所有这些代码实际上 意味着 ?
编译器确实理解了每个操作的含义:
int i = 1;
int* p = &i;
int j = *p;
p = nullptr;
int k = *p;
编译器甚至不会拒绝这个,即使第二个 *p
有未定义的行为。不编写该代码是你的工作,而不是编译器的工作来捕获它。