I'm working on a couple classes that, when finished, will allow binary I/O to files, strings, etc. Basic usage is:
Code:
mystream << binaryio::little_endian << binaryio::set_size(2) << my_integer;
So far, it's working wonderfully for strings. I plugged in the bit of code needed for file I/O, and everything crashed. I've boiled it down to the following small example:
Code:
#include <fstream>
#include <iostream>
int main()
{
unsigned char data[8];
std::basic_filebuf<unsigned char, std::char_traits<unsigned char> > bfs;
std::cerr << "About to open file..." << std::endl;
bfs.open("filetest", std::ios::in | std::ios::binary);
std::cerr << "Is file open? " << (bfs.is_open() ? "yes" : "no") << std::endl;
std::cerr << "Attempting read of 8 bytes." << std::endl;
try
{
std::streamsize ret;
ret = bfs.sgetn(data, 8);
std::cerr << "Got " << ret << " bytes." << std::endl;
}
catch(std::exception &e)
{
std::cerr << "Exception: " << e.what() << std::endl;
return 1;
}
return 0;
}
The program says that the file is open, and will get to the "Attempting read of 8 bytes" part, call basic_filebuf::sgetn(), and a "St8bad_cast" exception gets thrown. On my system, the backtrace at the time of the exception looks something like this:
Code:
std::__check_facet(NULL)
in bits/localefwd.h:187
std::basic_filebuf<unsigned char, std::char_traits<unsigned char> >::underflow()
std::basic_filebuf<unsigned char, std::char_traits<unsigned char> >::uflow()
std::basic_filebuf<unsigned char, std::char_traits<unsigned char> >::xsgetn()
std::basic_filebuf<unsigned char, std::char_traits<unsigned char> >::xsgetn()
std::basic_filebuf<unsigned char, std::char_traits<unsigned char> >::sgetn()
main()
Looking at the __check_facet function, all it does is check if it's parameter is NULL, and if so, throws the bad cast exception. The passed NULL is the value of std::basic_filebuf<...>::_M_codecvt.
Why is this (private) member NULL? Interestingly, if I change all occurrences of "unsigned char" to just "char", it works. However, I'm reading binary data, which to mean should be stored as unsigned char. Is there any way I can make this work? Do I need to modify/specialize std::traits? Also, why is locale even playing an issue here?
I see now that streambufs have a "pubimbue" and a "getloc" (getlocale and imbue locale) functions. Why? I thought streambufs handled reading/writing data to a stream, and that locale-dependant issues were the job of higher classes, such as istream/ostream/iostream?