2010-06-07 5 views
4

Il y a quelques jours, j'ai décidé qu'il serait amusant d'écrire une sous-classe streambuf qui utiliserait mmap et une lecture anticipée. J'ai regardé comment mon STL (SGI) mis en œuvre filebuf et s'est rendu compte que basic_filebuf contient un FILE*. Donc, hériter de basic_filebuf est hors de question.Dérivation de streambuf sans réécrire un flux correspondant

J'ai donc hérité de basic_streambuf. Ensuite, je voulais lier mon mmapbuf à un fstream.

Je pensais que la seule chose que je devrais faire serait de copier l'interface implicite de filebuf ... mais c'était une erreur évidente. Dans le SGI, basic_fstream possède un basic_filebuf. Peu importe si j'appelle basic_filestream.std::::ios::rdbuf(streambuf*), le flux de fichiers l'ignore complètement et utilise son propre filebuf.

Alors maintenant, je suis un peu confus ... bien sûr, je peux créer mon propre mmfstream, ce serait le copier/coller exact du fstream mais cela ne semble pas vraiment orienté vers le DRY.

Ce que je ne comprends pas, est la suivante: pourquoi ne fstream est si étroitement lié à filebuf, de sorte qu'il est impossible d'utiliser quoi que ce soit d'autre qu'un filebuf? Tout le point de séparer les flux et les bufs est que l'on peut utiliser un flux avec un tampon différent.

Solutions:

=>filestream doit reposer sur l'interface implicite de filebuf. Autrement dit, fstream devrait être modélisé par une classe streambuf. Cela permettrait à chacun de fournir sa propre sous-classe streambuf à fstream tant qu'il implémente l'interface implicite de filebuf. Problème: nous ne pouvons pas ajouter de paramètre de modèle à fstream, car il briserait les sélecteurs de gabarit tout en utilisant fstream comme paramètre de modèle de gabarit.

=>filebuf devrait être une classe virtuelle pure sans aucun attribut supplémentaire. De sorte que l'on peut en hériter sans porter tout son fICHIER *.

Vos idées sur le sujet?

+0

Vous avez une faute de frappe dans le sujet; streambug => streambuf. Je ne connais pas la réponse à votre question, désolé! – chrism1

+0

Corrigé, merci :) – NewbiZ

Répondre

2

Extrayez le mapped_file dans la bibliothèque Boost.Iostreams. Je n'ai jamais utilisé utilisé moi-même, mais il semble qu'il pourrait déjà faire ce dont vous avez besoin.

EDIT: Oups, relisez vos questions et je vois que vous le faites pour vous amuser. Peut-être que vous pouvez vous inspirer de Boost.Iostreams?

+0

Ouais j'ai bavardé avec un collègue ce matin et il m'a informé aussi que le boost l'avait déjà :) Mais comme tu l'as remarqué, c'est surtout pour le fun! Merci. – NewbiZ

2

fstream en soi n'est pas une grande classe. Il hérite de basic_stream pour prendre en charge toutes les opérations << et >>, contient un steambuf spécialisé qui doit être initialisé et les constructeurs correspondants pour transmettre les paramètres au constructeur streambuf. Dans un sens, ce que vous avez écrit à propos de votre solution basée sur un modèle est OK. Mais basic_stream peut également être dérivé dans un tcp_stream par exemple. Dans ce cas, les constructeurs de fstream sont un peu inutiles. Ainsi vous devez fournir une nouvelle classe tcpstream, héritant de basic_stream avec les paramètres corrects pour que les constructeurs puissent créer le tcp_stream. En fin de compte, vous n'utiliserez rien de fstream. Créer ce nouveau tcpstream est une question d'écriture de 3 ou 4 fonctions seulement. En fin de compte, vous dériveriez de la classe fstream sans aucune raison réelle de le faire. Cela ajouterait plus de couplage dans la hiérarchie de classe, couplage inutile.

+0

Je suis totalement d'accord avec la chose tcp_stream, car un flux tcp ne peut pas être manipulé comme un flux de fichier ou un flux de chaîne. Mais ici, nous parlons de deux streambuffers qui devraient être accessibles exactement de la même manière: ils manipulent tous les deux des fichiers, et devraient tous les deux être accessibles par filestream. Quel est le point d'avoir fstream et un fichierbuf dans différentes classes si vous ne pouvez pas utiliser l'un sans l'autre? – NewbiZ

+0

Je suis assez sûr que vous devrez fournir des paramètres supplémentaires (plus que ceux donnés à 'filebuf') à votre nouveau' streambuf'. Ainsi, vous devrez écrire de nouveaux constructeurs pour votre nouveau 'filestream'. Ces constructeurs sont la seule chose que vous devrez écrire, pour le créer, que ce soit en dérivant ou en étant autonome. –

+0

> Non, je vais devoir implémenter toutes les fonctionnalités supplémentaires de fstream: open, close, is_open, ... Et, le problème n'est pas d'écrire ces petites méthodes, c'est juste que je ne devrais pas avoir à le faire. Ce sera un copier/coller, pas de réutilisation de code. Plus important encore, mes utilisateurs devront passer de fstream à mmfstream, ce qui ne devrait pas être. – NewbiZ

1

Le point entier de std::fstream est que c'est un _ F _ile basé std::stream. Si vous voulez un std::stream ordinaire soutenu par votre mmstreambuf, vous devez créer un mmstreambuf et le transmettre à std::stream::stream(std::streambuf*)

+0

"Le point entier de std :: fstream est que c'est un fichier basé sur _F_ile std :: stream"> Et je ** veux ** un flux basé sur un fichier!Ma classe 'mmstreambuf' fournit exactement les mêmes caractéristiques que' filebuf', mais utilise de la mémoire mappée au lieu de la mémoire tampon. – NewbiZ

11

Dans les flux d'entrées-sorties de la conception, la plupart des flux réels de la fonctionnalité (par opposition à la fonctionnalité des tampons de flux) est implémenté en std::basic_istream, std::basic_ostream, et leurs classes de base. Les classes de chaînes de fichiers et de chaînes sont plus ou moins simplement des wrappers de commodité qui s'assurent qu'un flux avec le bon type de tampon est instancié.

Si vous souhaitez étendre les cours d'eau, vous presque toujours voulez fournir votre propre classe tampon de flux, et vous avez besoin presque jamais de fournir votre propre classe de flux. . Une fois que vous avez votre propre type de tampon de flux, vous pouvez ensuite en faire le tampon pour tout objet de flux que vous avez autour. Ou vous dérivez vos propres classes de std::basic_istream, std::basic_ostream et std::basic_iostream qui instancie votre tampon de flux et le transmet à leurs classes de base. Ce dernier est plus pratique pour les utilisateurs, mais vous oblige à écrire du code de plaque de chaudière pour l'instanciation du tampon (à savoir les constructeurs pour la classe de flux).

Pour répondre à votre question: Les flux de fichiers et le tampon de fichiers sont couplés si étroitement parce que le premier existe seulement pour faciliter la création de ce dernier. L'utilisation d'un flux de fichier facilite la configuration de tout.
L'utilisation de votre propre classe de flux pour envelopper la construction de votre propre tampon de flux ne devrait pas poser de problème, puisque vous ne devriez pas contourner les flux de fichiers, mais uniquement (références) aux classes de base.

+0

Je serais très intéressé de savoir pourquoi cela a été voté. – sbi

+3

Parce que vous n'avez pas répondu à la question. Rien écrit ici ne permet de résoudre le problème. C'est comme si vous vous parliez, répondant à une question imaginaire "quelle est la différence entre iostream et streambuf" ... – NewbiZ

+1

@ Aurélien: Juste point, sauf que j'ai certainement _meant_ de répondre à votre question. J'ai essayé de changer la réponse pour que cela devienne plus évident. – sbi

Questions connexes