Я пытаюсь записать некоторые двоичные данные в файл, используя std::basic_ofstream<std::uint8_t>, но он выдает bad_cast в __check_facet(). Я думаю, что каким-то образом я должен imbue() стрим с локалью, которая имеет std::codecvt<std::uint8_t, char, std::mbstate_t>, но я действительно не знаю, как это сделать.
Моя мотивация заключается в том, что я хотел бы отличать потоковые операторы, записывающие двоичные данные (версия std::uint8_t), от операторов, записывающих текстовые данные (char).
Он терпит неудачу, когда write вызывает __check_facet() и имеет нулевой указатель, поэтому выдает bad_cast.
(gdb) l
45 template<typename _Facet>
46 inline const _Facet&
47 __check_facet(const _Facet* __f)
48 {
49 if (!__f)
50 __throw_bad_cast();
51 return *__f;
52 }
#0 std::__check_facet<std::codecvt<unsigned char, char, __mbstate_t> > (__f=0x0) at /usr/include/c++/7/bits/basic_ios.h:50
#1 0x000055555555a1c0 in std::basic_filebuf<unsigned char, std::char_traits<unsigned char> >::xsputn (this=0x7fffffffdc38, __s=0x7fffffffdc2f "*X\311uUUU", __n=1)
at /usr/include/c++/7/bits/fstream.tcc:731
#2 0x0000555555557301 in std::basic_streambuf<unsigned char, std::char_traits<unsigned char> >::sputn (this=0x7fffffffdc38, __s=0x7fffffffdc2f "*X\311uUUU", __n=1) at /usr/include/c++/7/streambuf:451
#3 0x000055555555693c in std::basic_ostream<unsigned char, std::char_traits<unsigned char> >::_M_write (this=0x7fffffffdc30, __s=0x7fffffffdc2f "*X\311uUUU", __n=1) at /usr/include/c++/7/ostream:313
#4 0x00005555555560b0 in std::basic_ostream<unsigned char, std::char_traits<unsigned char> >::write (this=0x7fffffffdc30, __s=0x7fffffffdc2f "*X\311uUUU", __n=1)
at /usr/include/c++/7/bits/ostream.tcc:196
#5 0x0000555555555cb1 in main () at test.cpp:7
#include <fstream>
int main()
{
std::basic_ofstream<std::uint8_t> ofs("test.bin", std::ios_base::out | std::ios_base::binary);
std::uint8_t x = 42;
ofs.write(&x, 1);
ofs.close();
}
Проблема возникает только в Linux с g++ (в настоящее время используется 7.3.0), в Windows с msvc все работает нормально.
Редактировать:
В конце концов, я хотел бы добиться отдельных перегруженных операторов потока для двоичного и текстового вывода. Что-то вроде этого:
#include <fstream>
struct A
{
std::uint32_t number = 10;
};
std::ofstream& operator<<(std::ofstream& s, const A& a)
{
s << "The number is: " << a.number;
return s;
}
std::basic_ofstream<std::uint8_t>& operator<<(std::basic_ofstream<std::uint8_t>& s, const A& a)
{
s.write(reinterpret_cast<const std::uint8_t*>(&a.number), 4);
return s;
}
int main()
{
A a;
std::ofstream textFile("test.txt");
textFile << a;
textFile.close();
std::basic_ofstream<std::uint8_t> binaryFile("test.bin", std::ios_base::out | std::ios_base::binary);
binaryFile << a;
binaryFile.close();
}
Спасибо!
Кроме того, если вы просто хотите выполнить ввод-вывод двоичного файла, просто используйте write() с обычным std::ofstream.
Моя цель — иметь потоковые операторы для записи двоичных данных и для текста (например, для std::cout). У меня может возникнуть неправильное представление о реализации этого с помощью std::basic_ofstream<std::uint8_t>. Не могли бы вы порекомендовать что-то для достижения этого?
@face еще раз, просто используйте стандартный класс std::ofstream (также известный как std::basic_ofstream<char>). Вы уже строите с включенным флагом binary, просто введите данные в char* при передаче их в std::ofstream::write(), например: std::ofstream ofs("test.bin", std::ios_base::binary); ofs.write(reinterpret_cast<char*>(&x), sizeof(x));
Я понимаю, что это работает с простым std::ofstream, но я бы хотел 2 оператора для класса, один для двоичного кода, один для текста. Я не могу использовать два оператора с std::ofstream и по этому вопрос я не могу решить был ли поток бинарным или нет, поэтому я не могу сделать это с одним оператором.
Вот идея: напишите свой собственный класс «двоичного потока», который обертывает std::ofstream (или даже просто простой C FILE* для повышения производительности) и перегружайте operator<< для типов, которые вы хотите вставлять в свой собственный двоичный поток. Если файл предназначен для чтения разными компьютерами, вам придется учитывать порядок байтов закодированных данных.





Библиотека C++ не предоставляет локали/фасеты для потока
unsigned char. Спецификация C++ не требует, чтобы для этого использовалась библиотека C++. Для этого вам не нужен нестандартный объект файлового потока на основеuint8_t. Просто обычный, садовыйstd::oifstreamвполне подойдет.