Why does std::copy (from istream to ostream) raises an ios::failure exception?
The following code should copy data from an wifstream to wcout. After the content is copied, the program throws a ios::failure exception.
#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);
开发者_Go百科
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;
}
The stream should only throw an exception (see exception mask) if anything goes bad, but not on EOF.
To avoid skipping white space use the 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));
The exception:
The local may be using codecvt facet that is failing.
Try commenting out the locale line see what happens.
Have you tried to print what the exceptions is?
try
{
// do work
}
catch(std::exception const& e)
{
std::cout << e.what() << "\n";
}
Because you're using std::istream_iterator
, the attempt to read a character past the end of the stream sets both eofbit
and failbit
(and only after some error bits are set, does the iterator become equal to the end iterator)
Stripping to bare essentials and reverting to char to make it even simpler, program is equivalent to:
#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;
}
According to §27.6.1.2.3/10:
After a sentry object is constructed a character is extracted from in, if one is available, and stored in c. Otherwise, the function calls in.setstate(failbit).
So, when it reaches the end of the file and can no longer extract a character, it will set the fail bit, which you've set to produce an exception. Using std::copy
doesn't change the behavior -- an istream_iterator
reads via operator>>
.
You can copy the file a bit more easily:
std::wifstream is("test.ts", std::ios::binary);
std::wcout << is.rdbuf();
精彩评论