应该std :: ws在文件末尾提出failbit吗?

时间:2012-11-16 19:56:34

标签: c++ gcc clang iostream manipulators

应该使用std :: ws操纵器从流中提取是否会引发失败位?在下面的代码中,Clang编译(在Xcode 4.5.1中)程序会失败最终的断言。 EOF显然s >> std::ws导致失败。然而,GCC 4.7.2通过了断言。哪个是对的?

#include <iostream>
#include <sstream>
#include <cassert>

int main(int argc, const char * argv[])
{
    {
        // Read string with trailing ws.
        std::istringstream s( "test   " );
        std::string test;

        s >> std::ws;
        assert( !s.fail() );    // No ws to skip, but no failure.

        s >> test;
        assert( test == "test" );
        assert( !s.fail() );

        s >> std::ws;
        assert( !s.fail() );    // No prob skipping trailing ws.
    }
    {
        // Retry with no trailing ws.
        std::istringstream s( "test" );
        std::string test;

        s >> std::ws;
        assert( !s.fail() );    // No ws to skip, but no failure.

        s >> test;
        assert( test == "test" );
        assert( !s.fail() );

        s >> std::ws;
        assert( !s.fail() );    // CLANG: Skipping absent ws at eof raises failbit.
    }

    return 0;
}

2 个答案:

答案 0 :(得分:4)

我相信libc ++正在正确实施标准。

[我引用了N3290,这是C ++ 11标准草案。 C ++ 14不会改变这一点。 ]

[istream.manip]中描述了

ws,其中声明:

  

效果:表现为无格式输入功能(如   27.7.2.3,第1段),但不计算数量   提取的字符,不会影响返回的值   随后调用is.gcount()。构建一个岗哨对象后   只要下一个可用字符c是,就会提取字符   空格或直到序列中没有其他字符。   空白字符用相同的标准区分   由sentry :: sentry使用(27.7.2.1.3)。如果ws停止提取字符   因为没有更多可用它设置eofbit,但不是失败位。

确定正确行为的关键词是&#34;在构建岗哨对象后#34;

Sentry对象在[istream :: sentry]中描述,文本开始......

  

1类sentry定义了一个负责执行异常安全前缀和后缀操作的类。

     

显性哨兵(basic_istream&amp; is,bool noskipws = false);

     

2效果:如果is.good()为false,则调用is.setstate(failbit)。否则,准备   格式化或&gt;无格式输入。 ...... 等等 ...

这是唯一可用的哨兵构造函数,因此是libc ++使用的构造函数。

因此在提取任何字符之前设置失败位,因此段落末尾的文本不适用。如果流包含" "(即末尾的单个空格),则调用std::ws不会设置失败位,只是eof(这是OP预期会发生的)。

答案 1 :(得分:3)

C ++ 11,§27.7.2.4/ 1:

  

如果ws停止提取字符,因为没有更多可用字符,则设置eofbit,而不是failbit

因此,ws操纵器未直接设置failbit。但是,正如Marshall Clow在他的回答中指出的那样,它不需要 - 它需要创建一个岗哨对象,并且如果!stream.good(),则需要岗哨对象来设置故障位。