Подробности

[В начало]

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

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

num_get<>::do_get(bool) неверно работает в случае, когда одна целевая последовательность является префиксом другой

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

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

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.

Отсюда следует, что когда одна целевая последовательность (truename() или falsename()) является префиксом другой, прочитав меньшую последовательность из потока, функция должна продолжить чтение - чтобы найти уникальное соответствие (unique match). И только в случае, когда следующий символ в потоке не соответствует символу в большей последовательности (или когда в потоке нет больше символов, in == end), функция прерывает чтение. Этому случаю соответствует пример, приведеный в стандарте после описания функции do_get():

For targets true: "a" and false: "abb", the input sequence "a" yields val == true and err == str.eofbit.

Однако если следующий символ в потоке соответствует большей целевой последовательности, то функция должна продолжить чтение потока и проверить, что входная последовательность соответствует большей целевой последовательности. При этом факт совпадения части входной последовательности и меньшей целевой последовательности не играет роли. Этому случаю соответствует следующий пример из стандарта (при тех же строках, соответствующих true и false):

the input sequence "abc" yields err = str.failbit, with in ending at the ’c’.

Однако реализация в этом случае возвращает err==str.goodbit (нет ошибки), при этом в val записывается значение true. Содержимое потока после вызова функции - 'bc', а не 'c', как указано в примере. Это и демонстрирует приведённый ниже пример.

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

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>
#include <algorithm>
using namespace std;

class numpunct_my : public numpunct<char>
{
public:
    numpunct_my(size_t refs = 0) : numpunct<char>(refs) {}
protected:    
    ~numpunct_my(){};
    string do_truename() const{return "a";}
    string do_falsename() const{return "abb";}
};
int main()
{
    istringstream is("abс");
    is.imbue(locale(locale(), new numpunct_my()));
    bool result = false;
    is >> boolalpha >> result;
    
    if(is.rdstate() & ios_base::failbit)
        cout << "failbit was set." << endl;
    else
        cout << "failbit wasn't set, and result is " 
             << boolalpha << result << endl;
    string rest_of_stream;
    copy((istreambuf_iterator<char>)is,
         istreambuf_iterator<char>(),
         back_insert_iterator<string>(rest_of_stream)); 
    cout << "The rest of the stream is '" << rest_of_stream << "'." << endl;
    
    return 0;
}

Компонент

libstdc++

Принято

GCC Bugzilla 37957

Статус

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

[В начало]