Почему std :: copy (из istream в ostream) вызывает исключение ios :: fail? - PullRequest
8 голосов
/ 04 ноября 2010

Следующий код должен копировать данные из wifstream в wcout. После копирования содержимого программа выдает исключение ios :: fail.

#include <string>
#include <iostream>
#include <sstream>
#include <fstream>
#include <locale>
#include <iterator>
#include <algorithm>


int main(void)
{
    std::locale::global(std::locale(""));

    std::wifstream is;
    is.exceptions( std::ios::failbit | std::ios::badbit );
    is.open("test.ts", std::ios::binary);

    is >> std::noskipws;

    std::istream_iterator<wchar_t, wchar_t> in(is);
    std::istream_iterator<wchar_t, wchar_t> end;

    std::copy(in, end,
              std::ostream_iterator<wchar_t, wchar_t>(std::wcout));

    return 0;
} 

Поток должен генерировать исключение (см. Маску исключения), только если что-то идет не так, но не в EOF.

Ответы [ 3 ]

1 голос
/ 04 ноября 2010

Поскольку вы используете std::istream_iterator, попытка чтения символа после конца потока устанавливает оба значения eofbit и failbit (и только после установки некоторых битов ошибки итератор становится равнымконечный итератор)

Разобравшись с базовыми элементами и вернувшись к char, чтобы сделать его еще проще, программа эквивалентна:

#include <iostream>
#include <fstream>
int main()
{
    std::ifstream is("test.txt", std::ios::binary);
    is.exceptions(std::ios::failbit); // failbit only because that's what you get
    is >> std::noskipws;
    if(is)
        for(char c; is >> c;) // will throw!
            std::cout << c;
}
1 голос
/ 04 ноября 2010

Чтобы не пропускать пробелы, используйте std :: istreambuf_iterator

std::copy(std::istreambuf_iterator<wchar_t, wchar_t>(is),
          std::istreambuf_iterator<wchar_t, wchar_t>(),
          std::ostream_iterator<wchar_t, wchar_t>(std::wcout));

Исключение:

Возможно, локальный использует фасет codecvt, который не работает.
Попробуйте закомментироватьстрока локали посмотрим, что произойдет.

Вы пытались напечатать, что такое исключения?

try
{
    // do work
}
catch(std::exception const& e)
{
    std::cout << e.what() << "\n";
}
0 голосов
/ 04 ноября 2010

Согласно §27.6.1.2.3 / 10:

После того, как часовой объект построен, символ извлекается из в , если таковой имеется, и сохраняется в с .В противном случае функция вызывает in.setstate (failbit) .

Таким образом, когда он достигает конца файла и больше не может извлечь символ, он устанавливает ошибкубит, который вы установили для создания исключения.Использование std::copy не меняет поведения - istream_iterator читает через operator>>.

Вы можете скопировать файл немного проще:

std::wifstream is("test.ts", std::ios::binary);
std::wcout << is.rdbuf();
...