Подробности

[В начало]

Проблема в реализации № S0735

Краткое описание

num_get<>::do_get(bool) неверно выставляет флаг eofbit в случае boolalpha == true

Подробное описание

Из описания функции

iter_type do_get(iter_type in, iter_type end, ios_base& str, ios_base::iostate& err, bool& val) const

для случая, когда

(str.flags() & ios_base::boolalpha) != 0 (22.2.2.1.2):

(p15)Otherwise target sequences are determined "as if" by calling the members falsename() and truename() of the facet obtained by use_facet<numpunct<charT> >(str.getloc()). Successive characters in the range [in,end) (see 23.1.1) are obtained and matched against corresponding positions in the target sequences only as necessary to identify a unique match. The input iterator in is compared to end only when necessary to obtain a character. If and only if a target sequence is uniquely matched, val is set to the corresponding value.

Отсюда следует, что сравнение итераторов in и end будет происходить только тогда, когда последовательность, полученная из предыдущих вызовов (*in++), не совпадает ни с одной целевой последовательностью (truename() и falsename()), но может совпасть в будущем.
В частности, если truename = "true" и falsename = "false", то как только из потока были считаны символы 't', 'r', 'u', 'e', дальнейшего сравнения in и end не будет, хотя на этот момент возможно, что in == end.

(p16)The in iterator is always left pointing one position beyond the last character successfully matched. If val is set, then err is set to str.goodbit; or to str.eofbit if, when seeking another character to match, it is found that (in == end). If val is not set, then err is set to str.failbit; or to (str.failbit|str.eofbit) if the reason for the failure was that (in == end).

Отсюда следует, что флаг eofbit выставляется только тогда, когда при чтении последовательности из потока обнаружилось, что in == end. Это не эквивалентно тому, что после чтения последовательности in == end.
Однако реализация ведет себя так, что флаг eofbit выставляется тогда, когда на момент выхода из функции in == end (т.е эта проверка выполняется уже после того, как последовательность прочитана и выставлен/не выставлен результат).

Из-за этого, в частности, неверно выставляется значение err в следующих примерах, приведенных в стандарте после описания этой функции (22.2.2.1.2 p16):

For targets true: "1" and false: "0", the input sequence "1" yields val == true and err == str.goodbit. For empty targets (""), any input sequence yields err == str.failbit.

В первом примере реализация выдает err = str.eofbit, а во втором случае при пустом потоке (in == end изначально) - err = str.failbit | str.eofbit.

В приведенном ниже примере показывается поведение функции в случае, когда true соответствует строка "true", а false - "false" (значения целевых последовательностей в "C" локали, используемой по умолчанию), а входная последовательность - "true".
Согласно стандарту, флаг eofbit быть выставлен не должен, однако реализация его выставляет.

Раздел стандарта

Linux Standard Base C++ Specification 3.2, Chapter 9. Libraries, 9.1. Interfaces for libstdcxx, который ссылается на ISO/IEC 14882: 2003 Programming languages --C++, section 22.2.2.1.2

Пример

#include <iostream>
#include <sstream>
using namespace std;

int main()
{
    istringstream is("true");
    bool result;
    is >> boolalpha >> result;
    
    if(is.rdstate() & ios_base::eofbit)
        cout << "eofbit was set." << endl;
    else
        cout << "eofbit wasn't set." << endl;
    return 0;
}

Компонент

libstdc++

Принято

GCC Bugzilla 37958

Статус

Исправлено в gcc-4.4.0

[В начало]