【问题标题】:Closing files using fstream使用 fstream 关​​闭文件
【发布时间】:2016-03-20 18:41:59
【问题描述】:

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

例如

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

为什么编译器不能识别出你已经关闭了文件?

【问题讨论】:

  • 这不是编译器的责任。
  • 这更像是一个逻辑错误吗?我在想编译器会识别一个已经关闭的 ifstream 试图再次关闭并因此返回任何错误?
  • 这甚至不是逻辑错误,第二次调用根本没有做任何事情,因为inFile 没有打开的文件流。

标签: c++ fstream


【解决方案1】:

为什么编译器不能识别出你已经关闭了文件?

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

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

reference documentation可以看到:

注意事项

该函数在流对象超出范围时由basic_fstream的析构函数调用,通常不直接调用。

它甚至必须是幂等的。

【讨论】:

  • 上述代码是否有任何潜在危害,即关闭一个已经关闭的文件?我意识到我在代码中过于小心了,在几个地方我意识到我试图关闭一个已经关闭的文件。
  • 不,这只是浪费,因为你在做一些不必要的事情。
  • 第二次调用在运行时不会失败,标准明确说明会发生什么,两次调用没有错。
【解决方案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 具有未定义的行为,编译器也不会拒绝它。不编写代码是你的工作,而不是编译器的工作。

【讨论】:

    【解决方案3】:

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

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

    也许答案是:编译器不知道也不关心代码的运行时行为,而你所暗示的错误类型是运行时错误。

    【讨论】:

    • 这甚至不是错误,两次调用 close 完全有效且定义明确。
    • 同意乔纳森。正如我所说,他正在逃避运行时错误,而不是导致错误。 :)
    • 啊,我不明白答案的那部分......“暗示”:)
    猜你喜欢
    • 1970-01-01
    • 2021-06-27
    • 2018-02-23
    • 1970-01-01
    • 2013-01-18
    • 1970-01-01
    • 2013-10-31
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多