Извлечение из streambuf без перезаписи соответствующего потока - PullRequest
4 голосов
/ 07 июня 2010

Несколько дней назад я решил, что было бы интересно написать подкласс streambuf, который будет использовать mmap и упреждающее чтение. Я посмотрел, как мой STL (SGI) реализовал filebuf и понял, что basic_filebuf содержит FILE*. Так что наследование от basic_filebuf исключено.

Итак, я унаследовал от basic_streambuf. Затем я хотел связать свой mmapbuf с ручьем.

Я думал, что единственное, что мне нужно будет сделать, - это скопировать неявный интерфейс filebuf ... но это была явная ошибка. В SGI basic_fstream владеет basic_filebuf. Неважно, если я вызову basic_filestream.std::::ios::rdbuf( streambuf* ), файловый поток полностью игнорирует его и использует свой собственный filebuf.

Так что теперь я немного запутался ... конечно, я могу создать свой собственный mmfstream, который будет точной копией / вставкой fstream, но на самом деле это звучит не DRY-ориентированным.

Что я не могу понять, так это: почему fstream так тесно связан с filebuf, что невозможно использовать что-либо еще, кроме filebuf? Целое смысл разделения потоков и буферов состоит в том, что можно использовать поток с другим буфером.

Решения:

=> filestream должен полагаться на неявный интерфейс filebuf. То есть fstream должен быть настроен классом streambuf. Это позволило бы каждому предоставить свой собственный подкласс streambuf для fstream, если он реализует неявный интерфейс filebuf. Проблема: мы не можем добавить параметр шаблона в fstream, так как он сломает селекторы шаблона при использовании fstream в качестве параметра шаблона.

=> filebuf должен быть чисто виртуальным классом без каких-либо дополнительных атрибутов. Так что от него можно унаследовать, не неся весь его ФАЙЛ * мусор.

Ваши идеи на эту тему?

Ответы [ 4 ]

11 голосов
/ 07 июня 2010

В структуре потоков ввода-вывода большая часть функциональности реальных потоков (в отличие от функциональности потоковых буферов) реализована в std::basic_istream, std::basic_ostream и их базовых классах. Строковые и файловые классы потока являются более или менее просто вспомогательными оболочками, которые обеспечивают создание потока с правильным типом буфера .

Если вы хотите расширить потоки, вы почти всегда хотите предоставить свой собственный класс буфера потоков , и вам почти никогда не нужно предоставлять свой собственный класс потоков. ,

Если у вас есть собственный тип потокового буфера, вы можете сделать его буфером для любого объекта потока, который у вас есть. Или вы получаете свои собственные классы из std::basic_istream, std::basic_ostream и std::basic_iostream, которые создают экземпляр вашего потокового буфера и передают его своим базовым классам.
Последнее более удобно для пользователей, но требует от вас написания некоторого стандартного кода для создания экземпляра буфера (а именно конструкторов для класса потока).

Чтобы ответить на ваш вопрос: Файловые потоки и файловый буфер так тесно связаны, потому что первый существует только для того, чтобы облегчить создание второго. Использование файлового потока упрощает его настройку.
Использование собственного потокового класса для переноса конструкции собственного потокового буфера не должно быть проблемой, так как вы все равно не должны передавать потоки файлов, а только (ссылки) на базовые классы.

2 голосов
/ 07 июня 2010

Извлечение mapped_file в библиотеке Boost.Iostreams . Я никогда не использовал его сам, но кажется, что он уже может делать то, что вам нужно.

РЕДАКТИРОВАТЬ: Ой, перечитайте ваши вопросы, и я вижу, вы делаете это для удовольствия. Возможно, вы можете черпать вдохновение из Boost.Iostreams?

2 голосов
/ 07 июня 2010

fstream сам по себе не большой класс. Он наследуется от basic_stream для обеспечения поддержки всех операций << и >>, содержит специализированные steambuf, которые необходимо инициализировать, и соответствующие конструкторы для передачи параметров конструктору streambuf.

В некотором смысле, то, что вы написали о своем шаблонном решении, в порядке. Но basic_stream также может быть выведено в tcp_stream, например. В этом случае конструкторы fstream немного бесполезны. Таким образом, вам нужно предоставить новый класс tcpstream, унаследованный от basic_stream с правильными параметрами для конструкторов, чтобы можно было создать tcp_stream. В конце концов, вы не будете использовать ничего из fstream. Создание этого нового tcpstream - это написание только 3 или 4 функций.

В конце концов, вы бы унаследовали класс fstream без какой-либо реальной причины. Это добавит больше связи в иерархию классов, ненужное соединение.

1 голос
/ 07 июня 2010

Весь смысл std::fstream в том, что он основан на _ F _ile std::stream. Если вы хотите обычный std::stream, поддерживаемый вашим mmstreambuf, то вам нужно создать mmstreambuf и передать его std::stream::stream(std::streambuf*)

...