问题 交错读写有什么保证?


使用C ++时 std::iostream (例如, std::fstream 要么 std::stringstream,标准是否保证在同一个流上执行读写之间的关系?也就是说,如果我将数据写入一个,那是否正确 std::fstream,然后尝试从该流中读取数据,我应该看到我写的数据?怎么样的 std::stringstream?举个例子,这可以保证有效吗?

std::stringstream myStream;
myStream << "137 Hello 2.71828";

int myInt;
std::string myString;
double myDouble;

myStream >> myInt >> myString >> myDouble; // Parse as expected?

或者这个案子怎么样?

std::fstream myStream("some-file.txt", ios::in | ios::out);
myStream << "137 Hello 2.71828";

int myInt;
std::string myString;
double myDouble;

myStream >> myInt >> myString >> myDouble; // Parse as expected?

我问,因为我最近开发了一个网络流类,其中读取和写入不会相互影响(因为读取从网络拉出并写入通过网络发送)。就是写作

myNetworkStream << "Hi there!" << endl;

通过网络写,而

myNetworkStream >> myValue;

从网络上读取。我不确定这种行为是否与流的一般合同一致。如果我不得不猜测,以下三个中的一个可能持有:

  1. iostream 合同没有说明交错读写,或者
  2. 一般来说 iostream 合同没有说明交错读写,但规范中有一些特定的预设来管理标准类型如何 fstream 和 stringstream 工作,或
  3. iostream 合同确实说了一些关于交叉读取和写入的事情,这使得我的网络流类违反了。

我有一个规范的副本,但关于流的部分是如此密集和神秘,它几乎不可能遵循。如果有人能够确切地澄清如何 iostreams应该在你混合读写时表现,我真的很感激。


9148
2018-02-14 11:52


起源

在你的第二种情况下(带有“按预期解析?”的问题,你不会得到你所期望的,因为光标在流的末尾。为了读你所写的内容,你会必须将光标重置为流的开头。 - Zac Howland
此外,根据Langer / Kreft的说法,在双向文件流上写入后立即阅读,无需刷新和/或搜索,将导致不确定的结果。 (我没有查阅标准中的相关条款。) - Christopher Creutzig
@Zac Howland- Iostreams有两个游标,一个读取游标和一个写入游标。我的印象是这些是彼此独立的。您是否使用在写入后必须移动get指针? - templatetypedef
看到我的回答。据我所知,没有<iostream>的主流实现 不 使用C标准库的功能作为基础。 - DevSolar
有2个单独的游标。但是,除非您将其中一个移动到其他位置,否则默认情况下它们通常会保持同步。您可以通过打印出值来测试 tellp 和 tellg 完成写操作后。 - Zac Howland


答案:


我不确定该章的章节和诗句 C ++ 标准(我没有检查),但我非常熟悉 C 关于这个问题的标准(我  有...)。

C99声明可以在读,写或“更新”模式下打开流。只有后一种模式允许读取和写入相同的流,但(引用):

......输出不得直接输入,不得输入   干预呼吁 fflush 功能或文件定位功能(fseek,    fsetpos, 要么 rewind),输入不得直接跟随没有输出的输出   除非输入操作遇到,否则干预调用文件定位功能   档案结尾。

我假设C ++标准在某处说了类似的东西:你必须在读/写方向“反转”之前刷新或重新定位流。

编辑: 确实有两个单独的指针 - 可以查询 basic_istream::tellg 和 basic_ostream::tellp。但是,我发现提到两者的可能性  指向流中的相同位置仅与之相关 stringstream, 不是为了 fstream。结合上面的陈述,这是有道理的。尽管如此,仍然不能指出标准的章节和诗句。


10
2018-02-14 12:27



这听起来很正常,因为写入和读取通常具有不同的缓存。 - Alexandre C.
实际上,在我自己的C库实现中,读写使用了 相同 缓存,但以不同方式解释索引。我想这就是标准委员会的想法 - 否则会有额外的簿记和检查每个I / O访问。 - DevSolar
是的,C ++标准通过引用C标准对基于文件的流说了同样的话:“读取和编写由类basic_filebuf <charT,traits>的对象控制的序列的限制与读写相同使用标准C库文件。“请注意,相同的限制不适用于stringstream。 - Howard Hinnant
由于stringstreams仅作为内部缓冲区存在(没有外部表示,它们可能与它们不同步),因此不存在与缓冲相关的限制。因此,即使没有中间重新定位,我也希望它们能够正常运行。然而,作为一个偏执的开发者,我很重要 assert() 那个假设。 - DevSolar
我认为这里的基本原理不是一致性检查的开销,而是错误报告。如果我使用streambuf进行写操作,并且在缓冲区中有未提交的数据,那么需要我刷新这些数据的读取操作可能会返回一个刷新操作的错误,我发现从API点到视图。 - Simon Richter