libc++ std::istringstream не создает исключений. Ошибка?

После настройки std::istringstream для создания исключений, когда установлено failbit, я не получаю никаких исключений, происходящих с 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;
    }
}

вывод для libstdС++:

123
456
789
Fail

Вывод libС++/libcxxrt:

123
456
789
0

РЕДАКТИРОВАТЬ

Также протестировано на OS X.

Сообщение об ошибке отправлено: http://llvm.org/bugs/show_bug.cgi?id=15949< /а>


person pepper_chico    schedule 09.05.2013    source источник
comment
Возможно ли, что в ваших параметрах компиляции установлено _LIBCPP_NO_EXCEPTIONS?   -  person ecatmur    schedule 09.05.2013
comment
@ecatmur, нет, я не устанавливаю.   -  person pepper_chico    schedule 09.05.2013


Ответы (1)


libc++ отвечает на 27.7.2.1 [istream]/p4, который описывает basic_istream синтаксический анализ operator>> для unsigned:

Если одна из этих вызываемых функций выдает исключение, то, если явно не указано иное, входная функция устанавливает бэдбит в состояние ошибки. Если в exceptions() включен badbit, входная функция повторно выдает исключение, не завершая свои действия, в противном случае она ничего не выбрасывает и продолжает работу так, как если бы вызванная функция вернула индикацию ошибки.

If:

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

то желаемое поведение достигается.

123
456
789
Fail

Обновить

Чико правильно указал в комментариях ниже, что он ожидал, что getline(is, s, ',') выкинет, а не экстрактор unsigned.

Глядя на 21.4.8.9 [string.io]/p7, который описывает этот getline:

Эффекты: ведет себя как неформатированная функция ввода (27.7.2.3), за исключением того, что она не влияет на значение, возвращаемое последующими вызовами basic_istream‹>::gcount(). После построения объекта часового, если часовой преобразуется в значение true, вызывается функция str.erase(), а затем извлекается символы из is и добавляется к строке str, как если бы вызывалась функция str.append(1, c) до тех пор, пока не произойдет одно из следующих событий: . ..

Итак, вопрос становится:

Как ведет себя функция неформатированного ввода?

27.7.2.3 [istream.unformatted]/p1 говорит:

Каждая неформатированная входная функция начинает выполнение с создания объекта класса sentry с аргументом по умолчанию noskipws (второй) аргумент true. Если объект часового возвращает true, при преобразовании в значение типа bool функция пытается получить запрошенный ввод. В противном случае, если конструктор часового завершает работу, вызывая исключение, или если объект часового возвращает false, при преобразовании в значение типа bool функция возвращается, не пытаясь получить какие-либо входные данные. В любом случае количество извлеченных символов равно 0; неформатированные входные функции, принимающие массив символов ненулевого размера в качестве аргумента, также должны хранить нулевой символ (используя charT()) в первом месте массива. Если во время ввода возникает исключение, ios::badbit включается315 в *этом состоянии ошибки. (Исключения, выдаваемые из basic_ios‹>::clear(), не перехватываются и не создаются повторно.) Если (exceptions()&badbit) != 0, то исключение создается повторно. Также подсчитывается количество извлеченных символов. Если исключение не было выдано, оно завершается сохранением счетчика в объекте-члене и возвратом указанного значения. В любом случае сторожевой объект уничтожается перед выходом из неформатированной функции ввода.

315) Это делается без выдачи ios::failure.

(курсив добавлен мной для удобства чтения)

Таким образом, это снова указывает на то, что если требуется исключение из этой операции синтаксического анализа, badbit должно быть установлено в exceptions.

person Howard Hinnant    schedule 10.05.2013
comment
Имеет ли значение unsigned? std::getline(is, s, ','); - это строка, которая должна вызываться, она не требует чтения в unsigned. - person pepper_chico; 10.05.2013
comment
В конце концов у меня сложилось впечатление, почему это не может быть так просто? Если я не хочу устанавливать исключения для некоторых заданных флагов, просто установите их для них. Но нет, я должен вставить badbit из ниоткуда... - person pepper_chico; 10.05.2013
comment
Эта ошибка libc++ была закрыта как недопустимая, но я так не думаю . Причины установки failbit: en.cppreference.com/w/cpp /io/ios_base/iostate#The_failbit отличаются от причин, по которым устанавливается badbit: en.cppreference.com/w/cpp/io/ios_base/iostate#The_badbit Совершенно реалистично, что я могу захотеть только бросить, если был установлен failbit и < i>нет, если был установлен badbit. Из-за этого libc++ теперь требует кропотливого обходного пути, особенно для составных операторов извлечения: - person Jonathan Mee; 26.01.2016
comment
Я связал вопрос на LWG2349 в дубликате этого вопроса, и я считаю, здесь это также актуально: 35088800/ - person Jonathan Mee; 29.01.2016
comment
@HowardHinnant: Что должно делать создание объекта basic_istream::sentry? У меня нет копии Стандарта, но есть от cppreference похоже, что создание часового четвертого вызова std::getline() должно было обнаружить что eofbit уже установлено в is и, следовательно, должно было установить failbit (и при этом создать исключение). - person Tanz87; 29.08.2016
comment
@Tanz87: Вот ссылка на последний рабочий проект: open-std.org/jtc1/sc22/wg21/docs/papers/2016/n4606.pdf Там сказано, что для неформатированных функций часовой не должен пропускать пробел, и если часовой возвращает false, он должен установить badbit. - person Howard Hinnant; 29.08.2016
comment
@HowardHinnant: Спасибо. Обратите внимание, что вы сказали, что если часовой возвращает ложь.... Если часовой выдает исключение во время его построения, мы даже не дойдем до этого. В §27.7.2.1.3, абзац 1 (конструктор sentry): Эффекты: Если is.good() равно false, вызывает is.setstate(failbit). -- который, из §27.5.5.4, параграф 6 (метод basic_ios::setstate): Эффекты: Вызывает clear(rdstate() | state) (что может вызвать basic_ios::failure (27.5.3.1.1)). - person Tanz87; 29.08.2016
comment
Еще одна вещь: §27.7.2.3, параграф 1 (функции неформатированного ввода), говорит: если объект sentry возвращает true, при преобразовании в значение типа bool функция пытается получить запрошенный ввод. В противном случае, если конструктор sentry завершает работу, вызывая исключение, или если объект sentry возвращает false, при преобразовании в значение типа bool функция возвращается, не пытаясь получить какие-либо входные данные. Из этого может показаться, что getline не должен вызывать sentry отказ конструкции в виде исключения (эффективно противоречащего моему предыдущему комментарию)... ‹‹продолжение›› - person Tanz87; 29.08.2016
comment
Однако в §21.3.2.9 (getline для basic_string), параграф 9: Если функция не извлекает символы, она вызывает is.setstate(ios_base::failbit), что может вызвать ios_base::failure (27.5.5.4). -- Этот бит кажется дополнительным требованием к getline для basic_string (независимо от sentry - ошибки построения или ошибки при извлечении ввода), помимо того, что обычно требуется для неформатированных функций ввода. - person Tanz87; 29.08.2016
comment
@Tanz87: я рекомендую подать отчет об ошибке здесь, если вы считаете, что libc++ ошибается: llvm.org/bugs Я больше не являюсь сопровождающим libc++. - person Howard Hinnant; 29.08.2016