是否在两个不同的 fstreams 未定义行为中打开同一个文件?

Is opening the SAME file in two different fstreams Undefined Behaviour?

这个 has raised another interesting issue, as discussed in the .

总而言之:当随后尝试读取 写入数据 from/to 两个流 [=56= 时,OP 存在如下代码的问题]:

ifstream infile;
infile.open("accounts.txt");

ofstream outfile;
outfile.open("accounts.txt");

虽然问题本身已成功解决,但它提出了一个我找不到权威答案的问题(我对 Stack Overflow 和更广泛的网络进行了相当广泛的搜索)。

非常清楚地说明了调用已与 file[=44= 关联的 streamopen() 方法时发生的情况] (cppreference),但我找不到答案的是当(如本例中)文件 已经与(不同的).

If the stream is already associated with a file (i.e., it is already open), calling this function fails.

我可以在这里看到几种可能的情况:

  1. 第二个 open 调用将失败,任何试图写入它的尝试也会失败(但不是引用问题中的情况)。
  2. 第二个 open 调用将 'override' 第一个,有效地关闭它(这 可以 解释上述代码中遇到的问题)。
  3. 两个流都保持打开状态,但会进入关于其内部文件指针和缓冲区的 'mutual clobbering' 匹配。
  4. 我们进入了未定义(或实现定义)行为的领域。

请注意,由于第一个 open() 调用是由输入流进行的,因此操作系统不一定 'lock' 文件,因为它可能会对输出流。

那么,有人对此有明确的答案吗?或者来自标准的引用(cppreference 将是 'acceptable' 如果找不到更权威的)?

许多不同的平台都存在 C 实现,这些平台的底层文件系统可能会以不同方式处理此类极端情况。对于强制执行任何特定极端情况行为的标准,将使该语言仅在其文件系统以这种方式运行的平台上实用。相反,该标准认为此类问题不在其管辖范围内(即使用其自己的术语 "Undefined Behavior")。这并不意味着其目标 OS 提供有用保证的实现不应该在实际可行时对程序做出此类保证,但假定实现设计者比委员会更了解如何最好地为客户服务。

另一方面,实现 而不是 公开底层 OS 行为有时可能会有所帮助。例如,在没有明显 "append" 模式的 OS 上,但是需要 "open for append" 的代码可以执行 "open existing file for write" 后跟 "seek to end of file",一个当一个流写入文件的一部分,然后另一个流重写同一部分时,尝试打开两个流以附加到同一文件可能会导致数据损坏。对于检测该条件的实现注入其自己的逻辑以确保数据的顺利合并或阻止第二个打开请求可能会有所帮助。根据应用程序的目的,两种方法都可能更好,但是——如上所述——选择不在标准的管辖范围内。

basic_filebuf::open(以及所有依赖它的东西,比如 fstream::open)没有说明在这种情况下会发生什么。文件系统可能允许也可能不允许。

标准上说的是,如果文件打开成功,就可以按照界面播放了。如果它没有成功打开,则会出现错误。也就是说,该标准允许文件系统允许或禁止它,但它没有说明必须发生哪种情况。该实现甚至可以随机禁止它。或者禁止您以任何方式打开任何文件。所有(理论上)都是有效的。

对我来说,这甚至不属于 'implementation defined' 领域。根据底层文件系统或 OS(有些 OSes 禁止打开文件两次),完全相同的代码将有不同的行为。

没有

标准中没有讨论这种情况。

它甚至不由实现(您的编译器、标准库实现等)管理。

流最终请求操作系统以所需模式访问该文件,并且由操作系统决定此时是否应授予该访问权限。

一个简单的类比就是您的程序通过网络对 Web 应用程序进行 API 调用。也许 Web 应用程序不允许每分钟调用超过 10 次,如果您尝试超过 10 次,则 returns 一些错误代码。但这并不意味着您的程序在这种情况下具有未定义的行为。