【发布时间】:2020-10-05 07:49:01
【问题描述】:
我有以下代码:
#include <iomanip>
#include <iostream>
#include <sstream>
#include <string>
using namespace std;
int main(int argc, char* argv[]) {
stringstream buffer("1234567890 ");
cout << "pos-before: " << buffer.tellg() << endl;
buffer.ignore(10, ' ');
cout << "pos-after: " << buffer.tellg() << endl;
cout << "eof: " << buffer.eof() << endl;
}
它会产生这个输出:
pos-before: 0
pos-after: 11
eof: 0
我希望 pos-after 是 10 而不是 11。根据规范,当满足以下任一条件时,ignore 方法应该停止:
- 个字符已提取。在 count 等于
std::numeric_limits<std::streamsize>::max()的特殊情况下禁用此测试 - 文件结束条件出现在输入序列中,在这种情况下,函数调用 setstate(eofbit)
- 输入序列中的下一个可用字符 c 是 delim,由
Traits::eq_int_type(Traits::to_int_type(c), delim)确定。分隔符被提取并丢弃。如果 delim 为Traits::eof(),则禁用此测试
在这种情况下,我希望规则 1 在所有其他规则之前触发,并在流位置为 10 时停止。
Execution 表明情况并非如此。我误会了什么?
我还尝试了只忽略 9 个字符的代码变体。在这种情况下,输出是预期的:
pos-before: 0
pos-after: 9
eof: 0
所以看起来在ignore()提取字符数的情况下,它仍然检查下一个字符是否是delimiter,如果是,它也提取它。
我可以使用g++ 和clang++ 进行复制。
我也尝试了这种代码变体:
#include <iomanip>
#include <iostream>
#include <sstream>
#include <string>
using namespace std;
int main(int argc, char* argv[]) {
cout << "--- 10x get\n";
stringstream buffer("1234567890");
cout << "pos-before: " << buffer.tellg() << '\n';
for(int i=0; i<10; ++i)
buffer.get();
cout << "pos-after: " << buffer.tellg() << '\n';
cout << "eof: " << buffer.eof() << '\n';
cout << "--- ignore(10)\n";
stringstream buffer2("1234567890");
cout << "pos-before: " << buffer2.tellg() << '\n';
buffer2.ignore(10);
cout << "pos-after: " << buffer2.tellg() << '\n';
cout << "eof: " << buffer2.eof() << '\n';
}
结果是:
--- 10x get
pos-before: 0
pos-after: 10
eof: 0
--- ignore(10)
pos-before: 0
pos-after: -1
eof: 1
我们看到使用ignore() 会在文件上产生文件结束条件。表明ignore() 确实尝试在提取 10 个字符之后 提取一个字符。但在这种情况下,第 3 个条件被禁用,ignore() 不应该尝试查看下一个字符是什么。
【问题讨论】:
-
足够有趣的 Clang 10.0 打印 11 但 Clang 主干打印 10 (godbolt.org/z/ErKqon) 。 MSVC 还打印 10(本地测试)。
-
libstdc++ 错误gcc.gnu.org/bugzilla/show_bug.cgi?id=94749
-
谢谢,虽然它不可能是一个错误,因为 clang 和 gcc 同意(在我的机器上):)
-
这是一个标准库错误,而不是编译器错误。除非特别说明,否则 Clang 通常使用与 gcc 相同的标准库。