2009-08-15 49 views
15

有大量信息可用于重载operator<<以模仿将复杂对象转换为字符串的toString()样式方法。我对也感兴趣,执行反转,operator>>将字符串反序列化为对象。安全地重载流操作符>>

通过检查STL源,我收集的是:

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

将是反序列化Object类型的对象正确的函数签名。不幸的是,我一直在为如何正确实施这个 - 特别是如何处理错误一直在亏损:

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

回答

18
  1. 如何在流中指示无效数据?抛出异常?

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

stream.setstate(ios_base::failbit); 
  • 应该流是什么状态,是否有流中畸形数据?
  • 对于格式不符合您要阅读的格式的格式错误的数据,您通常应该设置fail位。对于内部流专用错误,使用bad位(例如,如果没有连接到流的缓冲区)。

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

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


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

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

    此外,请确保在尝试做任何事情之前检查“失败”位。如果它已经设置,只需返回流。 – KTC 2009-08-15 01:12:12

    +1

    感谢您的建议,特别是使用“失败”位而不是例外。除了设置失败位之外,我还必须对流的内容做出任何保证吗?例如,如果我设置了“失败”位,流应该保持不变吗? – 2009-08-15 01:15:45

    +0

    这就是我本来想说的,但你回答得更快!我想补充一点,正确的答案是通过查找现有的实现来实现的,这就是你所描述的。另外,我会注意到,不存在格式错误的数据,就像读取它的格式错误一样;在这种情况下,您需要确保变量不变,并且(如果您设置了失败位而不是坏位),那么没有字符从流中丢失。 – 2009-08-15 01:17:26

    0

    至于旗帜,我不知道是否有任何标准的地方,但它是一个好主意,重置它们。

    升压拥有该利落RAII包装:IO State Savers

    +0

    我不认为这是设计用于提取器,但用户代码。 – AProgrammer 2009-08-15 06:58:24

    +0

    我没有看到区别。他们也在输入流上工作,所以如果你想将标志设置回原来的状态,无论如何都要比手动更好。以奇怪方式影响流的提取器基本上已经损坏。 – Eugene 2009-08-15 07:16:00

    2

    一些其他注意事项:

    • 执行操作时>>,你或许应该考虑使用 bufstream,而不是运营商的其他重载> >;

    • 异常操作期间存在的应该被翻译到 failbit或badbit(流缓冲的成员可能抛出,取决于所使用的 类);

    • 设置状态可能抛出;如果您在捕获异常之后设置了状态,则应该传播原始异常,而不是传播setstate引发的异常,即 ;

    • 宽度是一个你应该注意的领域。如果您 把它考虑进去,你应该如果你使用的是其他运营商 >>做基础工作是重置为0,你要计算你逝去的 所收到的一个宽度;

    • 考虑考虑区域设置。

    兰格和Kreft(标准C++输入输出流和语言环境)CONVER这在甚至 更多细节。他们为错误处理提供了一个模板代码,该代码约为一页,需要 。

    +0

    为什么你建议使用'bustream'而不是其他重载(例如'istream')?我一定要看看Lange和Kreft的工作 - 听起来就像我在找的东西。 – 2009-08-15 22:15:35