libc ++ std :: istringstream不会抛出异常.错误?

pep*_*ico 6 c++ language-lawyer libc++

配置了一个std::istringstreamfailbit设置时抛出异常的时候我没有用libc ++发生异常(这是在linux下使用libc ++编译并在libcxxrt的支持下编译).我想这是libc ++或libcxxrt中的一个错误:

#include <iostream>
#include <sstream>

template<typename T> std::istream &getvalue(std::istream &is, T &value, const T &default_value = T())
{
    std::stringstream ss;
    std::string s;
    std::getline(is, s, ',');
    ss << s;
    if((ss >> value).fail())
        value = default_value;
    return is;
}

int main()
{
    std::string s = "123,456,789";
    std::istringstream is(s);
    unsigned n;

    try
    {
        is.exceptions(std::ios::failbit | std::ios::eofbit);

        getvalue(is, n);
        std::cout << n << std::endl;

        getvalue(is, n);
        std::cout << n << std::endl;

        // Disable EOF exception on last bit
        is.exceptions(std::ios::failbit);

        getvalue(is, n);
        std::cout << n << std::endl;

        // Force Fail reading after EOF
        getvalue(is, n);
        std::cout << n << std::endl;
    }
    catch(std::ios::failure &fail)
    {
        std::cout << "Fail" << std::endl;
    }
}
Run Code Online (Sandbox Code Playgroud)

libstdc ++的输出:

123
456
789
Fail
Run Code Online (Sandbox Code Playgroud)

libc ++/libcxxrt输出:

123
456
789
0
Run Code Online (Sandbox Code Playgroud)

编辑

也在OS X上测试过.

提交的错误:http://llvm.org/bugs/show_bug.cgi?id = 15949

How*_*ant 4

libc++ 正在响应 27.7.2.1 [istream]/p4,它描述了以下basic_istream内容的解析:operator>>unsigned

\n\n
\n

如果这些被调用函数之一引发异常,则除非另有明确说明,否则输入函数会将 badbit 设置为错误状态。如果 badbit 在 excepts() 中打开,则输入函数将重新抛出异常而不完成其操作,否则它不会抛出任何内容并继续执行,就像被调用的函数已返回失败指示一样。

\n
\n\n

如果:

\n\n
is.exceptions(std::ios::failbit | std::ios::badbit);\n
Run Code Online (Sandbox Code Playgroud)\n\n

然后获得所需的行为。

\n\n
123\n456\n789\nFail\n
Run Code Online (Sandbox Code Playgroud)\n\n

更新

\n\n

chico 在下面的评论中正确地指出,他希望getline(is, s, ',')扔出,而不是unsigned提取器。

\n\n

查看 21.4.8.9 [string.io]/p7 ,其中描述了这一点getline

\n\n
\n

效果:表现为未格式化的输入函数 (27.7.2.3),但它不影响后续调用 basic_istream<>::gcount() 返回的值。构造哨兵对象后,如果哨兵转换为 true,则调用 str.erase(),然后从 is 中提取字符并将其附加到 str,就像调用 str.append(1, c) 一样,直到出现任何字符发生以下情况:...

\n
\n\n

所以问题就变成了:

\n\n
\n

未格式化的输入函数如何表现?

\n
\n\n

27.7.2.3 [istream.unformatted]/p1 说:

\n\n
\n

每个未格式化的输入函数都通过使用默认参数 noskipws(第二个)\n 参数 true 构造\n 类 Sentry 的对象来开始执行。如果哨兵对象返回 true,则在转换为 bool 类型的值时,该函数将尽力获取请求的输入。否则,如果哨兵构造函数因抛出异常而退出,或者哨兵对象返回 false,则在转换为 bool 类型的值时,该函数将返回,而不会尝试获取任何输入。无论哪种情况,提取的字符数都设置为\n 0;采用非零大小的字符数组作为参数的未格式化输入函数也应在数组的第一个位置存储空字符(使用 charT())。如果在输入期间抛出异常,则 ios::badbit 将在 *this\xe2\x80\x99s 错误状态下打开315。 \n(从 basic_ios<>::clear() 抛出的异常不会被捕获或\n重新抛出。)如果 (exceptions()&badbit) != 0,则\n 重新抛出异常。它还计算提取的字符数。如果没有抛出异常,则通过将计数存储在成员对象中并返回指定的值来结束。无论如何,哨兵对象在离开未格式化的输入函数之前都会被销毁。

\n\n

315) 这样做不会导致抛出 ios::failure。

\n
\n\n

(为了便于阅读,我添加了重点)

\n\n

因此,这似乎再次表明,如果此解析操作需要异常,则badbit必须在exceptions.

\n

  • [这个 libc++ bug 被关闭为无效](https://llvm.org/bugs/show_bug.cgi?id=15949),但我不相信它是。设置 `failbit` 的原因:http://en.cppreference.com/w/cpp/io/ios_base/iostate#The_failbit 与设置 `badbit` 的原因不同:http://en.cppreference.com /w/cpp/io/ios_base/iostate#The_badbit 这是完全现实的,我可能只想*仅*在设置了“failbit”时抛出,而*不*在设置了“badbit”时抛出。因此,libc++ 现在需要一个艰苦的解决方法,特别是对于复合提取运算符:http://stackoverflow.com/a/35020134/2642059 (2认同)