【问题标题】:Safely overloading stream operator>>安全地重载流操作符>>
【发布时间】:2009-08-15 01:01:22
【问题描述】:

有大量关于重载operator<< 以模仿将复杂对象转换为字符串的toString() 样式方法的信息。我有兴趣实现逆向,operator>> 将字符串反序列化为对象。

通过检查STL 来源,我收集到:

istream &operator>>(istream &, Object &);

将是反序列化Object 类型对象的正确函数签名。不幸的是,我一直不知道如何正确实现这一点——特别是如何处理错误:

  1. 如何指示流中的无效数据?抛出异常?
  2. 如果流中有格式错误的数据,流应该处于什么状态?
  3. 在返回运算符链接的引用之前是否应该重置任何标志?

【问题讨论】:

    标签: c++ operator-overloading stream


    【解决方案1】:
    1. 如何指示流中的无效数据?抛出异常?

    您应该设置fail 位。如果流的用户想要抛出异常,他可以配置流(使用istream::exceptions),流会相应地抛出。我会这样做,然后

    stream.setstate(ios_base::failbit);
    
    1. 如果流中存在格式错误的数据,流应该处于什么状态?

    对于不符合您要读取的格式的格式错误的数据,您通常应该设置fail 位。对于内部流特定错误,使用bad 位(例如,如果没有缓冲区连接到流)。

    1. 在返回运算符链接的引用之前是否应该重置任何标志?

    我还没有听说过这样的事情。


    要检查流是否处于良好状态,您可以使用istream::sentry 类。创建它的一个对象,传递流和true(告诉它不要立即跳过空格)。如果设置了eoffailbad 位,则哨兵将评估为false

    istream::sentry s(stream, true);
    if(!s) return stream;
    // now, go on extracting data...
    

    【讨论】:

    • 还要确保在尝试执行任何操作之前检查fail 位。如果已经设置,只需返回流。
    • 感谢您的建议,尤其是使用 fail 位而不是异常。除了设置失败位之外,我还必须对流的内容做出任何保证吗?例如,如果我设置了fail 位,流是否应该保持不变?
    • 不使用流中的任何字符来获取格式错误的输入几乎是不可能的。你需要任意回溯。常见的行为是使用有效的前缀。
    • 在运算符中>>,就像对简单类型所做的那样(起初虽然浮点是这种情况下唯一的类型):返回失败并使用有效前缀。在用户代码中,您可以通过读取整行然后从字符串流中解析它来为您的用户提供更好的诊断。但是有时需要使用专为错误报​​告而设计的完整词法分析器/解析器。
    • 我只会使用有效的前缀。并保持不变。如果您需要在不实际消耗任何东西的情况下进行试探性解析,那么 I 将不再使用 iostreams。他们对此太不灵活了。我会使用 C 流或 iostreams 的低级 read 接口,并创建自己的预读缓冲区。
    【解决方案2】:

    一些补充说明:

    • 在实现运算符时>>,您可能应该考虑使用 bufstream 而不是 operator>> 的其他重载;

    • 操作过程中发生的异常应转换为 failbit 或 badbit(streambuf 的成员可能会抛出,具体取决于 使用的类);

    • 设置状态可能会抛出;如果你在捕获一个之后设置状态 异常,您应该传播原始异常而不是那个 由 setstate 抛出;

    • 宽度是一个需要注意的字段。如果你是 考虑到它,您应该将其重置为 0。如果您正在使用其他 operator>> 做基本工作,你必须计算你通过的宽度 从你收到的那个;

    • 考虑考虑区域设置。

    Lange 和 Kreft(标准 C++ IOStreams 和语言环境)甚至在 更多细节。他们为错误处理提供了一个模板代码 大约一页。

    【讨论】:

    • 您为什么建议使用bustream 而不是其他重载(例如istream?我一定会查看Lange 和Kreft 的工作——听起来就像我在寻找的一样。
    • 嗨,我看到 Michael 和 AProgrammer 都不太活跃,所以如果其他人看到这个:为什么 bustream 比重载更好?
    【解决方案3】:

    至于标志,我不知道某处是否有任何标准,但重置它们是个好主意。

    Boost 为此提供了简洁的 raii 包装器:IO State Savers

    【讨论】:

    • 我不认为这是设计用于提取器,而是用于用户代码。
    • 我看不出有什么不同。它们也适用于输入流,所以如果你想将标志设置回你可以设置的值,无论如何都比手动好。以奇怪的方式影响流的提取器基本上已损坏。
    猜你喜欢
    • 2020-08-08
    • 1970-01-01
    • 1970-01-01
    • 2022-11-04
    • 1970-01-01
    • 1970-01-01
    • 2011-07-18
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多