1

这里的这种说法似乎不正确:

另一方面,双向文件流没有隐式设置标志。这是因为双向流不必在所有情况下都处于输入和输出模式。您可能希望为只读或只写打开一个双向流。因此,双向文件流没有隐式输入或输出模式。您必须始终明确设置双向文件流的打开模式。

否则,此代码将无法编译。

#include <iostream>
#include <fstream>

using namespace std;

int main()
{
    fstream file("novo.txt", ios::out);
    char i;
    file >> i;
} 
4

2 回答 2

2

声明对于 gcc 是正确的

这里的这种说法似乎不正确:[…]

我不了解标准或 Visual Studio,但我知道我正在使用的 C++,它来自 GCC。在那里你可以看看相关的标题

oistream::open看起来像这样:

inline void
istream::open(const char* __s, ios_base::openmode __mode = ios_base::in) {
  if (!_M_filebuf.open(__s, __mode | ios_base::in))

所以你在这里有两件事:一个默认函数参数,以防你在调用方法时没有指定一个,以及一个强制标志,它总是 or-ed 进入提供的模式。因此,无论您指定哪种模式,输入模式都将始终添加到您的规范中。其他代码,特别是构造函数,将委托给它。类似的情况也会发生ofstream::open。另一方面,fstream::open具有默认参数,但没有强制参数:

inline void
fstream::open(const char* __s,
              ios_base::openmode __mode = ios_base::in | ios_base::out) {
  if (!_M_filebuf.open(__s, __mode))

因此,不通过任何模式是可以的(至少在这个实现中,但请阅读@kmote 的答案以获取更多详细信息),但是如果您确实通过了任何模式,那么您必须同时通过其中一个inout两个,因为您指定(或未能指定)的模式不会添加强制模式。

这是我阅读 Apache 文档的方式,源代码支持我的观点,至少对于我的实现而言。由于所有这些都在模板化代码中,因此您可以查看来自不同编译器的标头以了解它如何处理这些情况。所以看看 VS 头文件,看看basic_fstream它的方法是如何实现的。

缺少编译器错误

否则,此代码将无法编译。

您的代码打开一个双向流仅用于输出,然后尝试从中输入内容。没有理由编译失败。流的静态类型是fstream,即双向。只有在运行时,您才会将具有特定含义的特定标志传递给构造函数。编译器(通常)不会对此进行检查,因此当您的代码无法从流中实际读取时,您的代码将因此在运行时出现异常行为。

请注意,我不确定 Windows 是否真的支持打开文件仅用于输出。操作系统支持的唯一文件模式很可能是只读和读写。(请注意,我只是在这里推测。)在这种情况下,即使在运行时打开文件仅用于输出并随后从中读取也不会成为问题,因为out仅使用或使用in|out. 为了可移植性,应该选择正确的模式,因为那里有支持只写文件的内核。

于 2013-01-29T22:17:18.690 回答
1

尽管历史上对此事存在一些混淆,但我认为您引用的陈述确实具有误导性,但并非出于您示例中的原因。如文档中所述,双向文件流确实隐式设置了标志:

void open(
const char *_Filename,
ios_base::openmode _Mode = ios_base::in | ios_base::out,
int _Prot = (int)ios_base::_Openprot
);

根据 Apache 声明,我不希望您的代码示例失败,因为它明确地将标志设置为 ::out。另一方面,我希望这段代码会失败:

int main()
{
    fstream file("novo.txt");
    char i;
    file >> i;
} 

但是根据 MSDN 文档,此代码也不会失败,并且文件将默认为 ios_base::in & out(因此,Apache 语句并不完全准确)。

于 2013-01-29T21:28:32.467 回答