OVH Cloud OVH Cloud

problèmes avec les streams

19 réponses
Avatar
Frédéric Gourul
Bonjour à tous,

Je patauge lamentablement avec les streams. J'ai beau chercher avec mon ami
google et dans les archives du groupe, je ne parvient pas à en avoir une
vision clair.

A partir de la classe suivante:

class Test
{
public:
void put(const std::string& s);
void put(const char* buf, size_t buflen);
size_t get(std::string& s) const;
size_t get(char* buf) const;
};

Je voudrai créer une classe dérivée de ???stream pour pouvoir convertir les
données
récupérées enregistrement par enregistrement de ma classe pour les convertir
en flux et vice-versa.

J'ai essayé de m'inspirer de l'example de la FAQ, mais il n'utilise pas de
tampon et
je n'ai pas de fonction membre travaillant caractère par caractère. D'après
ce que
je vois, la gestion de tampon est completement pris en charge par streambuf,
mais
je ne sais pas comment la mettre en oeuvre.

Si quelqu'un ici pouvait mettre sur la voie et me montrer un exemple tous
simple de
ce qu'il faut faire, je suis preneur :)

Merci de votre aide.

9 réponses

1 2
Avatar
Samuel Krempp
le Monday 23 August 2004 09:14, écrivit :

class OSockStream : public SockBuf, public std::ostream {...}
class ISockStream : public SockBuf, public std::istream {...}


oui.
Sauf qu'en sachant que ces stream dérivent de Sockbuf (pluôt que d'en avoir
un comme membre) seulement de manière à ce que le SockBuf soit construit
avant le stream, on peut faire un héritage privé pour être clair.
pour rendre ça completement explicite, on peut définir un petit template
"base_for_member" et alors
class MonStream : private base_for_member<MonBuf>, public std::ostream ,
il n'y a pas besoin de bien connaitre les stream pour comprendre.

Le tout, ca va être d'écrire la classe SockBuf... c'est là où j'aurais
probablement besoin d'aide.


c'est pas très dur, il suffit de définir overflow / underflow pour y mettre
le code qui envoit les octets. On peut très bien faire ces envois par bloc,
c'est bien à ça que sert le concept de buffer dans streambuf.

Il faut juste comprendre que la base streambuf a besoin d'accéder au buffer
(et va s'y déplacer tout seul jusqu'à ne plus pouvoir), et que donc c'est
dans streambuf que sont stockés les pointeurs de (début, courant, fin) de
buffer.
La classe dérivée y accède par les fctions héritées :
(pbase, pptr, epptr) en sortie
et (eback, gptr, egptr) en entrée)
et les mets à jour par setg / setp & pbump.

Pour mes classes de fichier, je n'ai pas besoin de streambuf, car en fait,
ces classes s'occupent déja des opérations de lecture/écriture sur le
média. Ce sont des classes héritée d'un passé C, j'ai juste encapsulée les
fonctions dans des classes (elles utilisent fread/fwrite pour lire/écrire
sur le fichier).


ben tant qu'à faire, autant les encapsuler en leur donnant une interface
streambuf directement (i.e. en dérivant de streambuf), plutôt qu'une
interface spécifique suivie d'une surcouche pour en faire un streambuf..
En plus des fonctions dont je parlais, pour des fichiers faut aussi
redéfinir les fctions de seek (qui vont faire un fseek, et mettre à jour le
buffer en conséquence).

Je le pourrais à usage personnel, mais déja plus difficilement
professionnellement (j'ai déja du mal à faire mettre à jour mon
compilateur...).


Inclure des headers boost n'a pas bcp de conséquences par rapport à changer
de compilateur : ça n'affecte pas ceux qui ne veulent pas utiliser boost..
Je me demande dans quelle proportion d'entreprises utiliser boost est
impossible.

Mais j'ai bien l'impression que tout ce que je cherche se
trouve dans la STL, suffit juste que j'apprenne à les utiliser...


oui probablement. je comprends pas tout ce que tu veux faire. Mais dans un
premier temps visiblement il s'agit juste de définir des streambufs custom,
et ça c'est parfaitement prévu par la SL.

--
Sam

Avatar
Frédéric Gourul
"Samuel Krempp" a écrit dans le
message de news: 4129c665$0$7009$
le Monday 23 August 2004 09:14, écrivit :

class OSockStream : public SockBuf, public std::ostream {...}
class ISockStream : public SockBuf, public std::istream {...}


oui.
Sauf qu'en sachant que ces stream dérivent de Sockbuf (pluôt que d'en
avoir

un comme membre) seulement de manière à ce que le SockBuf soit construit
avant le stream, on peut faire un héritage privé pour être clair.
pour rendre ça completement explicite, on peut définir un petit template
"base_for_member" et alors
class MonStream : private base_for_member<MonBuf>, public std::ostream ,
il n'y a pas besoin de bien connaitre les stream pour comprendre.


Exact, erreur de recopie: j'avais effectivement mis un héritage privé sur
SockBuf...

Il faut juste comprendre que la base streambuf a besoin d'accéder au
buffer

(et va s'y déplacer tout seul jusqu'à ne plus pouvoir), et que donc c'est
dans streambuf que sont stockés les pointeurs de (début, courant, fin) de
buffer.
La classe dérivée y accède par les fctions héritées :
(pbase, pptr, epptr) en sortie
et (eback, gptr, egptr) en entrée)
et les mets à jour par setg / setp & pbump.


J'ai très sommairement étudiées ces fonctions et je devrais y arriver avec
ce qu'elles proposent. La seule chose dont je ne suis pas sûr c'est pour le
buffer. Je dois le mettre dans la classe SockBuf et utiliser
streambuf::setbuf avec l'adresse de mon buffer et sa taille, c'est bien ca ?

Inclure des headers boost n'a pas bcp de conséquences par rapport à
changer

de compilateur : ça n'affecte pas ceux qui ne veulent pas utiliser boost..
Je me demande dans quelle proportion d'entreprises utiliser boost est
impossible.


Il n'y aura surement aucun problème si je le demandais (juste le temps que
ca prendra avant de l'avoir). Mais alors, il me faudra expliquer pourquoi,
or jusqu'a présent je n'en ai pas eu besoin. Les développements c++ sont
très récents dans l'entreprise et ne sont même pas encore utilisés en
production...


Avatar
Samuel Krempp
le Monday 23 August 2004 12:48, écrivit :

J'ai très sommairement étudiées ces fonctions et je devrais y arriver avec
ce qu'elles proposent. La seule chose dont je ne suis pas sûr c'est pour
le buffer. Je dois le mettre dans la classe SockBuf et utiliser
streambuf::setbuf avec l'adresse de mon buffer et sa taille, c'est bien ca
?


presque, sauf que streambuf::setbuf ne fait rien du tout :)
(à toi de le redéfinir dans ta classe dérivée si tu veux)

Dans SockBuf, tu alloues de la mémoire, et tu files les pointeurs de début /
fin à setp (ou setg).
Les fonctions que j'ai évoquées dans le msg d'avant sont les charnières
entre la base et la classe dérivée pour les streambuf, les autres sont plus
des "options".

Inclure des headers boost n'a pas bcp de conséquences par rapport à
changer

de compilateur : ça n'affecte pas ceux qui ne veulent pas utiliser
boost.. Je me demande dans quelle proportion d'entreprises utiliser boost
est impossible.


Il n'y aura surement aucun problème si je le demandais (juste le temps que
ca prendra avant de l'avoir). Mais alors, il me faudra expliquer pourquoi,
or jusqu'a présent je n'en ai pas eu besoin.


tu n'as pas besoin de smart pointers ? c'est tellement utile en C++, et
boost::smart_ptr est particulierment bien faite. et très très polyvalente.
à elle seule elle vaut largement le coup d'utiliser boost. (d'autant qu'il
ya juste besoin des headers, comme pour 90% de boost)

boost::static_assert, aussi, est une lib d'utilité quasiment universelle.

ensuite, la serialization sans effort est à priori aussi qque chose de
presque universellement utile (mais c'est en CVS. la branche 1.32 est sur
le point d'être créée, en gros d'ici 1 mois ou 2 sortira la release)

Les autres librairies de boost sont d'usage plus ou moins spécifique (mais
gagnent à être connues, quand le besoin se présente ça épargne de commencer
à réinventer la roue).
regex, random (la solution basique d'utiliser le rand de base est souvent
trop imprécise), ...

J'ai du mal à imaginer un développement où *aucune* des librairies de boost
ne serait utile. ya tellement de petites libs bien pratiques..

Les développements c++ sont
très récents dans l'entreprise et ne sont même pas encore utilisés en
production...


ah bah d'autant plus, c'est le moment de partir sur des bases saines
alors ! :)

--
Sam


Avatar
Loïc Joly
Samuel Krempp wrote:

tu n'as pas besoin de smart pointers ? c'est tellement utile en C++, et
boost::smart_ptr est particulierment bien faite. et très très polyvalente.
à elle seule elle vaut largement le coup d'utiliser boost. (d'autant qu'il
ya juste besoin des headers, comme pour 90% de boost)

boost::static_assert, aussi, est une lib d'utilité quasiment universelle.

ensuite, la serialization sans effort est à priori aussi qque chose de
presque universellement utile (mais c'est en CVS. la branche 1.32 est sur
le point d'être créée, en gros d'ici 1 mois ou 2 sortira la release)

Les autres librairies de boost sont d'usage plus ou moins spécifique (mais
gagnent à être connues, quand le besoin se présente ça épargne de commencer
à réinventer la roue).
regex, random (la solution basique d'utiliser le rand de base est souvent
trop imprécise), ...


J'ajouterai aussi le duo function/bind. C'est tellement utile que ça
fait partie de ce qui est en train d'être ajouté au C++, et c'est ce que
des langages concurents mettent en avant comme fonctions qu'ils on mais
pas le C++ (sous le nom de delegate, par exemple).

--
Loïc

Avatar
Frédéric Gourul
"Samuel Krempp" a écrit dans le
message de news: 4129d85c$0$13692$
le Monday 23 August 2004 12:48, écrivit :

J'ai très sommairement étudiées ces fonctions et je devrais y arriver
avec


ce qu'elles proposent. La seule chose dont je ne suis pas sûr c'est pour
le buffer. Je dois le mettre dans la classe SockBuf et utiliser
streambuf::setbuf avec l'adresse de mon buffer et sa taille, c'est bien
ca


?


presque, sauf que streambuf::setbuf ne fait rien du tout :)
(à toi de le redéfinir dans ta classe dérivée si tu veux)

Dans SockBuf, tu alloues de la mémoire, et tu files les pointeurs de début
/

fin à setp (ou setg).
Les fonctions que j'ai évoquées dans le msg d'avant sont les charnières
entre la base et la classe dérivée pour les streambuf, les autres sont
plus

des "options".


ok, merci bien. Avec tout ca, je ne devrais plus avoir de problème.

tu n'as pas besoin de smart pointers ? c'est tellement utile en C++, et
boost::smart_ptr est particulierment bien faite. et très très polyvalente.
à elle seule elle vaut largement le coup d'utiliser boost. (d'autant qu'il
ya juste besoin des headers, comme pour 90% de boost)


si si... comment s'en passer ?
Je les ai faites moi-même à titre d'apprentissage...
Et je me suis pour beaucoup inspiré de boost pour la version finale.
Oui je sais... j'ai réinventé la roue... j'adore ca :)

boost::static_assert, aussi, est une lib d'utilité quasiment universelle.


ca, j'avoue ne pas connaitre... Vu le nom, je suppose que ca permet
de vérifier des préconditions (sur les types ?) à la compilation.

ensuite, la serialization sans effort est à priori aussi qque chose de
presque universellement utile (mais c'est en CVS. la branche 1.32 est sur
le point d'être créée, en gros d'ici 1 mois ou 2 sortira la release)


Le jour où j'aurais besoin de sérialization, je crois que je n'hésiterais
pas: boost.

Les autres librairies de boost sont d'usage plus ou moins spécifique (mais
gagnent à être connues, quand le besoin se présente ça épargne de
commencer

à réinventer la roue).
regex, random (la solution basique d'utiliser le rand de base est souvent
trop imprécise), ...


Tout à fait, il n'empêche que parfois la complexité de certaines libs soit
rebutante, car on a besoin que d'une toute petite partie et que la lib
traite le cas général. Ne me demande pas d'exemple pour boost, je n'en ai
pas. Et il se peut que ma remarque soit infondée pour boost. Il se trouve
que je n'ai pas eu encore le temps d'apréhender cette librairie. je suis sûr
de ne même pas avoir vu la moitié de ce qui est dispo dans la SL. Mais je
sais que boost existe et je connais la plupart des domaines qui sont y
couvert, c'est donc là en premier que j'irai regarder lorsque le besoin se
fera sentir.


Avatar
kanze
"Frédéric Gourul" wrote in message
news:<cgci71$vfc$...
"Samuel Krempp" a écrit dans
le message de news: 4129c665$0$7009$


[...]
Inclure des headers boost n'a pas bcp de conséquences par rapport à
changer de compilateur : ça n'affecte pas ceux qui ne veulent pas
utiliser boost.. Je me demande dans quelle proportion d'entreprises
utiliser boost est impossible.


Il n'y aura surement aucun problème si je le demandais (juste le temps
que ca prendra avant de l'avoir). Mais alors, il me faudra expliquer
pourquoi, or jusqu'a présent je n'en ai pas eu besoin. Les
développements c++ sont très récents dans l'entreprise et ne sont même
pas encore utilisés en production...


Tu n'as que ne pas démander. Boost est gratuit ; tu le télécharges, et
tu l'installes chez toi au moins dans un premier temps.

La raison principale que j'ai vue pour ne pas se servir de Boost, c'est
que Boost est quand même assez moderne, et le porter à certains
compilateurs anciens posent de problèmes. Alors, si tu es obligé à te
servir d'un de ces compilateurs...

Sinon, ça serait vraiment dommage de s'en priver.

--
James Kanze GABI Software http://www.gabi-soft.fr
Conseils en informatique orientée objet/
Beratung in objektorientierter Datenverarbeitung
9 place Sémard, 78210 St.-Cyr-l'École, France, +33 (0)1 30 23 00 34


Avatar
Frédéric Gourul
A partir des informations collectées, j'ai fait une petite version de test
de ma future classe SockStreamBuf.
Pour l'instant, ca écrit et ca lit dans un fichier...


class TestBuffer : public std::streambuf
{
protected:
static const int BUFFER_SIZE = 8;
char m_buffer[BUFFER_SIZE];
FILE* m_file;

TestBuffer(FILE* file);

private:
streambuf* setbuf(char_type* s, streamsize n);
int_type underflow();
int_type overflow(int_type c);
int sync();
};

TestBuffer::TestBuffer(FILE* file) :m_file(file)
{
setbuf(m_buffer, BUFFER_SIZE);
}

streambuf* TestBuffer::setbuf(char_type* s, streamsize n)
{
streambuf::setp(s, s + n);
streambuf::setg(s, s + n, s + n);
return this;
}

streambuf::int_type TestBuffer::underflow()
{
size_t n = ::fread(m_buffer, 1, BUFFER_SIZE, m_file);
if (n == -1) return traits_type::eof();
if (n == 0 && ::feof(m_file)) return traits_type::eof();

streambuf::setg(eback(), eback(), eback() + n);
return traits_type::not_eof(*eback());
}

streambuf::int_type TestBuffer::overflow(streambuf::int_type c)
{
size_t n = ::fwrite(m_buffer, 1, BUFFER_SIZE, m_file);
if (n != BUFFER_SIZE) return traits_type::eof();

m_buffer[0] = c;
streambuf::setp(pbase(), epptr());
streambuf::pbump(1);
return traits_type::not_eof(c);
}

int TestBuffer::sync()
{
if (pptr() == pbase()) return 0;
streamsize len = pptr() - pbase();
size_t n = ::fwrite(m_buffer, 1, len, m_file);
if (n != len) return -1;
streambuf::setp(pbase(), epptr());
return 0;
}

class OTestStream : TestBuffer, public std::ostream
{
public:
OTestStream(FILE* file)
:TestBuffer(file), std::ostream(this) {}
};

class ITestStream : TestBuffer, public std::istream
{
public:
ITestStream(FILE* file)
:TestBuffer(file), std::istream(this) {}
};


Même si ce n'est qu'une version de test, toutes les critiques sont les
bienvenues :)

Il y a un certain nombre d'opérations qui n'ont pas de sens pour les sockets
(je pense en particulier aux fonctions seek), je ne les ai donc pas
implémentées... Est-ce suffisant ou faut-il que j'en fournisse un
implémentation qui renverait une erreur (exception ?)

Je me suis appercu que le déclenchement de sync() se faisait avec std::endl,
mais pas avec std::ends. Pour quelle raison ?

Le dernier, je m'y attendais... sur le ITestStream l'operateur >> considère
l'espace comme séparateur au lieu du caractère LF. Y'a-t-il un moyen de
changer ce comportement ?

merci
Avatar
kanze
"Frédéric Gourul" wrote in message
news:<cgd8j5$erv$...

A partir des informations collectées, j'ai fait une petite version de
test de ma future classe SockStreamBuf. Pour l'instant, ca écrit et ca
lit dans un fichier...

class TestBuffer : public std::streambuf
{
protected:


Pourquoi « protected », et non « private » ?

static const int BUFFER_SIZE = 8;
char m_buffer[BUFFER_SIZE];
FILE* m_file;

TestBuffer(FILE* file);

private:


Et pourquoi « private » ici, quand elles sont « protected » dans la
classe de base ? (Aussi, je le trouve plus propre de repéter le
« virtual », pour que le lecteur le voit tout de suite.)

streambuf* setbuf(char_type* s, streamsize n);
int_type underflow();
int_type overflow(int_type c);
int sync();
};

TestBuffer::TestBuffer(FILE* file) :m_file(file)
{
setbuf(m_buffer, BUFFER_SIZE);
}

streambuf* TestBuffer::setbuf(char_type* s, streamsize n)
{
streambuf::setp(s, s + n);
streambuf::setg(s, s + n, s + n);
return this;
}


Normalement, « setbuf » est conçu pour être appelée (à travers
pubsetbuf) de l'extérieur, pour que l'utilisateur puisse fournir un
buffer. Dans la plupart des implémentations que je connais, le buffer
est en fait alloué dynamiquement dans le premier appel à overflow ou à
underflow, et uniquement si l'utilisateur n'a pas appelé setbuf avant.
(Il y a aussi un drapeau pour dire si le buffer nous appartient ou non,
de façon à pouvoir le libérer ou non dans le destructeur.)

Dans un streambuf personel, je m'en passe souvent ; si je sais que je ne
vais pas appeler setbuf, ce n'est pas la peine de l'implémenter. Dans la
gestion des sockets, d'ailleurs, je pourrais imaginer une politique de
gestion de buffers qui exclut l'utilisation d'un buffer utilisateur, et
donc, où setbuf renvoie toujours NULL.

En tout cas, dans cette optique-là, je ne m'en servirai pas pour
positionner mon buffer à moi. Dans la mésure où tu veux toujours te
servir de ton buffer, l'implémentation de setbuf dans la classe de base
(qui renvoie toujours une erreur) convient. Dans ce cas-ci, aussi, il me
semble parfaitement acceptable que le buffer fasse partie de l'objet
(plutôt que d'être alloué dynamiquement). En revanche, je ne vois aucun
intérêt de les positionner dans le constructeur.

Et en passant, je ne vois pas comment ça va marcher d'utiliser le même
buffer en entrée et en sortie pour un socket. Ça marche pour un fichier,
évidemment, parce que tu dois rélire ce que tu as écrit ; la suite
virtuelle est identique pour les entrées et les sorties. Ce n'est pas le
cas pour un socket.

streambuf::int_type TestBuffer::underflow()
{


Selon la norme, cette fonction ne doit être appelée que si le buffer est
vide. Dans la pratique, dans les anciens flux, ce n'était pas toujours
le cas, et histoire de prévenir, je commence toujours mes
implémentations par une vérification du genre :

if ( gptr() >= egptr() )

size_t n = ::fread(m_buffer, 1, BUFFER_SIZE, m_file);
if (n == -1) return traits_type::eof();
if (n == 0 && ::feof(m_file)) return traits_type::eof();


if ( n == 0 )

tout simplement. n ne serait jamais -1 -- ça signifierait qu'on a lu
SIZE_MAX éléments.

streambuf::setg(eback(), eback(), eback() + n);


Pourquoi faire simple quand on peut faire compliquer ?

setg( m_buffer, m_buffer, m_buffer + n ) ;

Dans la pratique, quand on lit et écrit sur un fichier, il est plus ou
moins nécessaire de garder les deux pointeurs (écriture et lecture)
alignés. Dans ce cas-ci, donc, je répositionnerais aussi les pointeurs
d'écriture :

setp( m_buffer, m_buffer + n ) ;

Mais c'est un caractèristique des fichiers ; pour un socket, j'aurais
deux buffers séparés, et alors, évidemment, la lecture n'influe pas sur
la position d'écriture, ni vice versa.

return traits_type::not_eof(*eback());


Je ne suis pas sûr que not_eof fait ce que tu veux. La norme dit :

yields e if X::qu_int_type(e,X::eof()) if fales, otherwise a value f
such that X::eq_int_type(f,X::eof()) is false.

Or, dans ton cas, `e', c'est le résultat de la conversion implicite d'un
char (souvent signé) en int -- le résultat risque fort d'être négatif.

Je crois que la fonctiom que tu veux, c'est traits_type::to_int_type().
(Personnellement, j'écrirai simplement (unsigned char)m_buffer[0]. Mais
je suis un vieux, qui a appris les iostream avant la norme, et qui doit
encore supporter d'anciens compilateurs, qui n'implémentent pas la
norme.)

}

streambuf::int_type TestBuffer::overflow(streambuf::int_type c)
{


Attention ! overflow, c'est un peu plus compiquer, parce que la norme ne
donne aucune garantie que le buffer est plein. (Il garantit que si le
buffer est plein, et on essaie d'ajouter un caractère, overflow sera
appelé, mais il ne garantit pas qu'il ne serait pas appelé autrement.)
Aussi, elle admet la possibilité que c vaut EOF, et que dans ce cas-là,
il ne faut pas l'ajouter à la suite. (Historiquement, on appelait
overflow avec c == EOF pour provoquer un flush(). Je n'en sais pas où il
en est maintenant.)

Donc :

size_t n = ::fwrite(m_buffer, 1, BUFFER_SIZE, m_file);
if (n != BUFFER_SIZE) return traits_type::eof();


if ( pptr() - pbase() > 0 ) {
size_t n = ::fwrite( pbase(), 1, pptr() - pbase(), m_file ) ;
if ( n < pptr() - pbase() ) {
return traits_type::eof() ;
}
}

m_buffer[0] = c;
streambuf::setp(pbase(), epptr());
streambuf::pbump(1);


setp( m_buffer, m_buvffer + BUFFER_SIZE ) ;
if ( ! traits_type::eq_int_type(c,traits_type::eof())) {
sputc( traits_type::to_char_type( c ) ) ;
}
return traits_type::not_eof(c);
}


Un autre alternatif, que j'aime assez, c'est en fait de déclarer ou
d'allouer un char de plus dans le buffer que ce qu'on annonce par setp.
Du coup, même si pptr() == epptr(), on peut écrire le caractère à pptr()
avant d'écrire le buffer (y compris le caractère) sur disque. Quelque
chose comme :

int_type result = EOF ;
char* end = pptr() ;
if ( c != EOF ) {
*end ++ = c ;
}
size_t n = fwrite( pbase(), 1, end - pbase(), m_file ) ;
if ( n == end - pbase() ) {
setp( m_buffer, BUFFER_SIZE ) ;
result = 0 ;
}
return result ;

Dans le cas des flux sur fichiers, évidemment, il faut poser la question
des effets de l'écriture sur les entrées. Ici aussi, j'appelerais aussi
setg. (Mais seulement dans le cas des fichiers -- comme j'ai dit
ci-dessus, pour les socket, j'utiliserais deux buffers distincts.)

int TestBuffer::sync()
{
if (pptr() == pbase()) return 0;
streamsize len = pptr() - pbase();
size_t n = ::fwrite(m_buffer, 1, len, m_file);
if (n != len) return -1;
streambuf::setp(pbase(), epptr());
return 0;
}


Ou bien, sync() appelle overflow( EOF ), ou bien, overflow() appelle
sync(). Je ne dupliquerais pas le code.

class OTestStream : TestBuffer, public std::ostream


J'écrirai le private explicitement.

{
public:
OTestStream(FILE* file)
:TestBuffer(file), std::ostream(this) {}
};

class ITestStream : TestBuffer, public std::istream
{
public:
ITestStream(FILE* file)
:TestBuffer(file), std::istream(this) {}
};

Même si ce n'est qu'une version de test, toutes les critiques sont les
bienvenues :)

Il y a un certain nombre d'opérations qui n'ont pas de sens pour les
sockets (je pense en particulier aux fonctions seek), je ne les ai
donc pas implémentées... Est-ce suffisant ou faut-il que j'en
fournisse un implémentation qui renverait une erreur (exception ?)


L'implémentation par défaut dans streambuf même renvoie une erreur.
C'est ce qu'il faut pour les socket, je crois.

Je me suis appercu que le déclenchement de sync() se faisait avec
std::endl, mais pas avec std::ends. Pour quelle raison ?


Parce que c'est ce que la norme dit:-).

En fait, ce sont deux choses différentes. endl, c'est bien pour renvoyer
un 'n' puis synchroniser -- c'est un peu pour simuler ce qu'on appelait
autrefois « line buffered ». ends, en revanche, c'est un peu comme le
fait d'écire un fin de fichier, et n'a de sens que sur un strstream. Or,
dans le cas d'un strstream, sync() est un no-op.

Le dernier, je m'y attendais... sur le ITestStream l'operateur >>
considère l'espace comme séparateur au lieu du caractère LF.


C'est la définition de >> vers une chaîne.

Y'a-t-il un moyen de changer ce comportement ?


On pourrait faire jou-jou avec le locale, mais à mon avis, le plus
simple, c'est simplement utiliser la requête qui convient : si tu veux
lire une ligne, et non un mot, la fonction s'appelle getline.

--
James Kanze GABI Software http://www.gabi-soft.fr
Conseils en informatique orientée objet/
Beratung in objektorientierter Datenverarbeitung
9 place Sémard, 78210 St.-Cyr-l'École, France, +33 (0)1 30 23 00 34

Avatar
Frédéric Gourul
a écrit dans le message de news:


merci pour toutes ces remarques judicieuses...

grâce à vous tous, j'ai fait quelques progrès sur les streams :)
1 2