【问题标题】:libc++ std::istringstream doesn't thrown exceptions. Bug?libc++ std::istringstream 不会抛出异常。漏洞?
【发布时间】:2013-05-09 18:06:47
【问题描述】:

在配置std::istringstream 以在设置failbit 时引发异常后,我没有发现libc++ 发生异常(这是在Linux 下,在libcxxrt 的支持下编译的libc++)。我想这是 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;
    }
}

libstdc++ 的输出:

123
456
789
Fail

libc++/libcxxrt 输出:

123
456
789
0

编辑

也在 OS X 上测试过。

Bug 提交:http://llvm.org/bugs/show_bug.cgi?id=15949

【问题讨论】:

  • 你的编译选项中是否设置了_LIBCPP_NO_EXCEPTIONS
  • @ecatmur,不,我没有设置它。

标签: c++ language-lawyer libc++


【解决方案1】:

libc++ 正在响应 27.7.2.1 [istream]/p4,它描述了 basic_istream 解析 operator&gt;&gt;unsigned

如果这些被调用函数之一抛出异常,则除非 另有明确说明,输入函数错误地设置了 badbit 状态。如果 badbit 在 exceptions() 中打开,则输入函数重新抛出 异常没有完成它的动作,否则它不会 抛出任何东西并继续进行,就好像被调用的函数返回了一个 故障指示。

如果:

is.exceptions(std::ios::failbit | std::ios::badbit);

然后获得所需的行为。

123
456
789
Fail

更新

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

查看 21.4.8.9 [string.io]/p7 描述了这个getline

效果:表现为未格式化的输入函数 (27.7.2.3),除了 它不会影响后续调用返回的值 basic_istream::gcount()。在构造一个哨兵对象后,如果 sentry 转换为 true,调用 str.erase() 然后提取 来自 is 的字符并将它们附加到 str 就好像通过调用 str.append(1, c) 直到出现以下任何一种情况:...

所以问题变成了:

未格式化的输入函数的行为如何?

27.7.2.3 [istream.unformatted]/p1 说:

每个未格式化的输入函数通过构造一个 具有默认参数 noskipws 的哨兵类对象(第二个) 论据为真。如果 sentry 对象返回 true,则转换为 bool 类型的值,函数努力获取请求的 输入。否则,如果哨兵构造函数通过抛出一个 异常或如果哨兵对象返回 false,则在转换为 bool 类型的值,函数返回而不尝试获取 任何输入。在任何一种情况下,提取的字符数都设置为 0;采用非零字符数组的未格式化输入函数 size 作为参数也应该存储一个空字符(使用 charT()) 在数组的第一个位置。 如果过程中抛出异常 输入然后 ios::badbit 在 *this 的错误状态下打开315。 (从 basic_ios::clear() 抛出的异常不会被捕获或 重新抛出。)如果 (exceptions()&badbit) != 0 那么异常是 重新抛出。 它还计算提取的字符数。如果不 异常已被抛出它通过将计数存储在成员中来结束 对象并返回指定的值。无论如何,哨兵 对象在离开未格式化的输入函数之前被销毁。

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

(出于可读性目的,我添加了重点)

所以这似乎再次表明,如果此解析操作需要异常,则必须在 exceptions 中设置 badbit

【讨论】:

猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2022-01-18
  • 2014-11-29
  • 2010-09-13
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多