0

在实施basic_filebuf时我偶然发现basic_filebuf::pbackfail并且不完全理解它的定义。

来自cplusplus.com

Moves the current input position on position back to point to the previous character and, if supported, makes c available as that next character to be read.

If the implementation does not support writing to putback positions, c shall either match the character at the putback position or be the end-of-file value (traits_type::eof()). Otherwise, the function fails. [...]

If the get pointer (gptr) is at the beginning of the character sequence before the call, the function may either fail or make additional putback positions available and succeed, depending on the library implementation.

或来自cppreference

1) The caller is requesting that the get area is backed up by one character (pbackfail() is called with no arguments), in which case, this function re-reads the file starting one byte earlier and decrements basic_streambuf::gptr(), e.g. by calling gbump(-1).
2) The caller attempts to putback a different character from the one retrieved earlier (pbackfail() is called with the character that needs to be put back), in which case
a) First, checks if there is a putback position, and if there isn't, backs up the get area by re-reading the file starting one byte earlier.
a) Then checks what character is in the putback position. If the character held there is already equal to c, as determined by Traits::eq(to_char_type(c), gptr()[-1]), then simply decrements basic_streambuf::gptr().
b) Otherwise, if the buffer is allowed to modify its own get area, decrements basic_streambuf::gptr() and writes c to the location pointed to gptr() after adjustment.

所以本质上两者都说输入位置递减(除非它在文件的开头)并且可能放回一个字符。所以以下应该成功(假设根据注释准备文件,使用标准类来比较行为):

std::fstream f(..., in | out | binary);
f.get() // == 'a'
f.get() // == 'b'
f.sync(); // or f.seekg(0)
f.putback('b');
f.putback('a');
f.putback(); // may fail

然而,在 libc++ 上,第一次回退已经失败,并检查我发现pbackfailif (__file_ && this->eback() < this->gptr())aka 保护的源代码“如果有一个打开的文件并且当前读取缓冲区的前面有空间”。

刷新/同步/搜索清除读取缓冲区,这解释了失败的放回。当使用无缓冲 IO 时,读取缓冲区中只有一个字符空间,因此(至少)第二次放回即使没有刷新也会失败。或者第二次获取可能会跨越缓冲区“边界”,这意味着“b”将是当前缓冲区中的第一个字符,这也会导致第二次回退失败。

问题:如何准确指定回退?尽管 cppreference 和 cplusplus 似乎都暗示读取位置在任何情况下都会递减,但它似乎仅在 get 后立即有效。如果他们是对的,是 libc++ 不符合标准还是我遗漏了什么?

4

1 回答 1

0

问题:如何准确指定回退?

它在istream.unformatted部分中指定。

但是,这指的是sputbackc,您可能还想阅读一般的流缓冲区要求

于 2019-12-04T15:17:08.623 回答