Std::basic_ofstream<std::uint8_t> сбой записи в __check_facet()

Я пытаюсь записать некоторые двоичные данные в файл, используя 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();
}

Спасибо!

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

Sam Varshavchik 31.03.2019 20:36

Кроме того, если вы просто хотите выполнить ввод-вывод двоичного файла, просто используйте write() с обычным std::ofstream.

Cruz Jean 31.03.2019 20:38

Моя цель — иметь потоковые операторы для записи двоичных данных и для текста (например, для std::cout). У меня может возникнуть неправильное представление о реализации этого с помощью std::basic_ofstream<std::uint8_t>. Не могли бы вы порекомендовать что-то для достижения этого?

face 31.03.2019 20:46

@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));

Remy Lebeau 31.03.2019 23:54

Я понимаю, что это работает с простым std::ofstream, но я бы хотел 2 оператора для класса, один для двоичного кода, один для текста. Я не могу использовать два оператора с std::ofstream и по этому вопрос я не могу решить был ли поток бинарным или нет, поэтому я не могу сделать это с одним оператором.

face 01.04.2019 08:08

Вот идея: напишите свой собственный класс «двоичного потока», который обертывает std::ofstream (или даже просто простой C FILE* для повышения производительности) и перегружайте operator<< для типов, которые вы хотите вставлять в свой собственный двоичный поток. Если файл предназначен для чтения разными компьютерами, вам придется учитывать порядок байтов закодированных данных.

Emile Cormier 20.05.2020 00:58
Стоит ли изучать PHP в 2026-2027 годах?
Стоит ли изучать PHP в 2026-2027 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Приемы CSS-макетирования - floats и Flexbox
Приемы CSS-макетирования - floats и Flexbox
Здравствуйте, друзья-студенты! Готовы совершенствовать свои навыки веб-дизайна? Сегодня в нашем путешествии мы рассмотрим приемы CSS-верстки - в...
Тестирование функциональных ngrx-эффектов в Angular 16 с помощью Jest
В системе управления состояниями ngrx, совместимой с Angular 16, появились функциональные эффекты. Это здорово и делает код определенно легче для...
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
1
6
412
0

Другие вопросы по теме