C++ - 如果自定义提取器失败,如何恢复 istream

C++ - How to recover istream if self defined extractor fails

本文关键字:何恢复 恢复 istream 如果 自定义 提取 失败 C++      更新时间:2023-10-16

我需要一个自定义提取器(运算符>>(来读取特定字符串到我自己的数据类型中。

问题是对字符串的要求很大。

因此,最简单的方法可能是从 istream 中读取整个字符串,然后检查是否满足所有要求。

我的问题是字符串是否无效。据我所知,C++流保持不变是很常见的。

在这种情况下,恢复 istream 的最佳实践是什么?以下示例中的异常处理是否足够?

std::istream& operator>>(std::istream& is, Foo& f)
{
    std::string str;
    if (is >> str)
    {
        // check if string is valid
        if ( is_valid( str ) )
        {
            // set new values in f
        }
        else
        {
            // recover stream
            std::for_each(str.rbegin(), str.rend(),
                          [&] (char c)
            {
                is.putback(c);
            });
            // ste failbit
            is.clear(std::ios_base::failbit);
        }
    }
    return is;
}

那么 std::getline(( 而不是>> str 呢?还有其他陷阱吗?

谢谢

马可

您无法将流恢复到开始阅读的初始位置,至少在一般情况下是这样。理论上,您可以放回字符或查找到以前去过的位置,但许多流缓冲区不支持放回字符或查找。标准库提供了一些有限的指导,但它处理的是相当简单的类型,例如整数:只要格式匹配并且它就在那里停止,字符就会被读取。即使格式匹配,也可能存在一些可以更早检测到的错误。

下面是一个演示标准库行为的测试程序:

#include <iostream>
#include <sstream>
void test(std::string const& input)
{
    std::istringstream in(input);
    int i;
    std::string tail;
    bool result(in >> i);
    in.clear();
    std::getline(in, tail);
    std::cout << "input='" << input << "' "
              << "fail=" << std::boolalpha << result << " "
              << "tail='" << tail << "'n";
}
int main()
{
    test("10 y");
    test("-x y");
    test("0123456789 x");
    test("123456789012345678901234567890 x");
}

只是为了解释四个测试用例:

  1. 只是为了确保测试执行它应该做的事情,第一个输入实际上是可以的,没有问题。
  2. 第二个输入以与格式匹配的字符开头,后跟不匹配的内容,读取在'-'字符之后立即停止。
  3. 第三个测试使用八进制数字读取int。可能在字符'8'上检测到故障,但'8''9'都会消耗,输入也会失败。
  4. 最后一个示例会导致溢出,可以在读取所有数字
  5. 之前检测到溢出,但仍会读取所有数字。

基于此,我认为当对格式正确的输入进行语义检查失败时,不会期望将流重置到原始位置。