Derivación de StreamBuf sin reescribir una transmisión correspondiente
Pregunta
Hace algunos días, decidí que sería divertido escribir un streambuf
subclase que usaría mmap
y leer. Miré cómo se implementó mi STL (SGI) filebuf
y me di cuenta de que basic_filebuf
contiene una FILE*
. Así que heredando de basic_filebuf
está fuera de discusión.
Entonces heredé de basic_streambuf
. Entonces quería atar a mi mmapbuf
a un fstream.
Pensé que lo único que tendría que hacer sería copiar la interfaz implícita de filebuf
... Pero ese fue un claro error. En el SGI, basic_fstream
posee un basic_filebuf
. No importa si llamo basic_filestream.std::::ios::rdbuf( streambuf* )
, el FileStream lo ignora por completo y usa su propio filebuf
.
Así que ahora estoy un poco confundido ... Claro, puedo crear el mío mmfstream
, esa sería la copia/pegar exacta del fstream
Pero eso suena realmente no orientado a seco.
Lo que no puedo entender es: por que fstream
está tan bien junto con filebuf
, para que no sea posible usar nada más que un filebuf
? El punto completo de separar corrientes y BUF es que se puede usar una transmisión con un búfer diferente.
Soluciones:
=> filestream
debe confiar en la interfaz implícita de filebuf
. Es decir, Fstream debe ser plantado por una clase StreamBuf. Eso permitiría a todos proporcionar su propia subclase StreamBuf a un fstream
Mientras se implementa filebuf
La interfaz implícita. Problema: no podemos agregar un parámetro de plantilla a fstream
ya que rompería los selectores de plantilla mientras usa fstream
Como parámetro de plantilla de plantilla.
=> filebuf
Debe ser una clase virtual pura sin ningún atributo adicional. Para que uno pueda heredar de él sin llevar todo su archivo* basura.
Tus ideas sobre el tema?
Solución
Verificar Mapped_file en el Boost.iostreams biblioteca. Nunca lo he usado yo mismo, pero parece que ya podría hacer lo que necesitas.
EDITAR: Vaya, vuelva a leer sus preguntas y veo que está haciendo esto por diversión. ¿Quizás puedas inspirarte en Boost.iostreams?
Otros consejos
En el diseño de las transmisiones de IO, la mayor parte de la funcionalidad de las transmisiones reales (a diferencia de la funcionalidad de los buffers de flujo) se implementa en std::basic_istream
, std::basic_ostream
, y sus clases base. Las clases de transmisión de cadenas y archivos son más o menos solo envolturas de conveniencia, lo que se asegura de que se instancia una secuencia con el tipo correcto de búfer.
Si quieres extender las transmisiones, Casi siempre quieres proporcionar tu Clase de búfer de transmisión propia, y casi nunca necesitas proporcionar tu propia clase de transmisión. .
Una vez que tenga su propio tipo de búfer de transmisión, puede convertirlo en el búfer para cualquier objeto de transmisión que tenga. O deriva sus propias clases de std::basic_istream
, std::basic_ostream
, y std::basic_iostream
lo que instancia su búfer de transmisión y pasarlo a sus clases base.
Este último es más conveniente para los usuarios, pero requiere que escriba algún código de placa de caldera para la instanciación del búfer (es decir, constructores para la clase de flujo).
Para responder a su pregunta: las transmisiones de archivos y el búfer de archivos se acoplan tan estrechamente porque el primero solo existe para aliviar la creación de la segunda. El uso de una transmisión de archivo facilita la configuración de todo.
Usar su propia clase de transmisión para envolver la construcción de su propio búfer de transmisión no debería ser un problema, ya que no debería pasar las transmisiones de archivos de todos modos, sino solo (referencias) a las clases base.
fstream
En sí mismo no es una gran clase. Hereda de basic_stream
para proporcionar apoyo a todos los <<
y >>
operaciones, contiene un especializado steambuf
que deben inicializarse y los constructores correspondientes para pasar los parámetros al streambuf
constructor.
En cierto sentido, lo que escribió sobre su solución templada está bien. Pero basic_stream
También se puede derivar en un tcp_stream
por ejemplo. En ese caso, los constructores de fstream
son un poco inútiles. Por lo tanto, necesita proporcionar un nuevo tcpstream
clase, heredando de basic_stream
con los parámetros correctos para que los constructores puedan crear el tcp_stream
. Al final, no usarías nada de fstream
. Creando este nuevo tcpstream
es cuestión de escribir 3 o 4 funciones solamente.
Al final, derivarías del fstream
clase sin ninguna razón real. Esto agregaría más acoplamiento en la jerarquía de clase, acoplamiento innecesario.
El objetivo de std::fstream
es que es un _F_ILE basado en std::stream
. Si quieres un ordinario std::stream
respaldado por tu mmstreambuf
, entonces deberías crear un mmstreambuf
y pasarlo a std::stream::stream(std::streambuf*)