kanze@gabi-soft.fr Guest
|
Posted: Fri Sep 05, 2003 11:40 am Post subject: Re: surcharge de l'opérateur d'entrée |
|
|
Samuel Krempp <krempp (AT) crans (DOT) trucs.en.trop.org> wrote
| Quote: | le Jeudi 4 Septembre 2003 22:19, [email]mnana.net (AT) wanadoo (DOT) fr[/email] écrivit :
char * s = new char[strlen(buffer)+1];
strcpy(s,buffer);
chaine chain(s);
istr>>chain;
tout le code parait assez bizarre, voir peu orthodoxe. En particulier
ici, si je lis bien, l'operator>> s'appelle récursivement ?
|
Je le crois aussi. Mais j'avoue, je me suis arrêté à l'utilisation de
getchar pour lire des caractères dans un operator>>. C-à-d qu'il lit de
stdin, quelque soit le istream. Pas très catholique, à mon avis. (Déjà,
stdio et istream ensemble, ça ne fait pas de bon ménage.)
En somme, pour lire une « chaine » depuis un fichier, il lit cinq
caractères de l'entrée standard, puis s'appelle la même fonction pour
récommencer, jusqu'à ce qu'il en a marre, et fait un ^C, ou le système a
marre de lui filer des pages pour la pile, et fait un SIGSEGV (ou son
équivalent sous Windows).
| Quote: | lorsque j'essaie de créer une classe en utilisant cette déclaration
il n'ya pas d'arret qd j'entre les valeur et pourtant je ne devrais
pouvoir en rentrer que 5
|
Ça, c'est sûrement la faute de l'appel récursif. Avec un peut de
perséverence, tu arriveras à un moment où il s'arrête. À cause d'un
débordement de la pile.
Tiens, c'est marrant. Personne n'a rélevé que main doit renvoyer int, et
non void. Ce n'est pas grave (et ce n'est certainement pas la source de
son problème), mais ça fait que ton programme ne compile pas avec tous
les bons compilateurs.
| Quote: | {
chaine s;
cin>>s;
en passant, mélanger utilisations de cin et stdin (via getchar()) est
-il me semble- problématique. genre, probablement undefined behaviour.
ou alors j'ai rêvé.
|
Il a écrit « void main ». Il est donc sous Windows, probablement avec
VC++. Donc, la bibliothèque Dinkumware. Qui synchronise cin et stdin, je
crois. Mais c'est une extension. Une garantie supplémentaire. Je ne sais
pas si c'est un comportement indéfini, mais c'est sûr que lequel des
deux flux lit quel caractère n'est pas spécifié. (Pas de réformattage du
disque dûr, mais on ne sait toujours pas ce qu'on va lire.)
En l'occurance, dans ce programme-ci, il ne lit que de stdin. Parce que
l'opérateur >> qu'il appelle ne lit jamais du flux qu'il a été passé .
Ça se discute pour les types d'assez bas niveau. Il y en a qui disent
qu'il faut utiliser le streambuf directement. (Personellement, j'utilise
le streambuf parce que je m'y connais, mais je crois que les deux
solutions sont également valable. Pour des types de bas niveau -- je
n'accepterais pas qu'on utilise des streambuf pour, disons, Complex,
plutôt que de se servir des conversions vers double tout faites dans
istream.)
| Quote: | en sachant qu'il n'y a pas moyen d'accéder à chaque caractèree *dès*
qu'il est tapé en C++ sans recourir à des fonctions du système.
|
Ou à une bibliothèque portable qui le fait pour toi, du genre curses.
Mais notre poster original n'en est pas là, je crois.
| Quote: | (sinon, il faut attendre que le système les passe à cin, i.e. qd on
appuie sur entrée)
|
Ou plus généralement, que le système fait ce qu'il veut. Il y a des
systèmes gentils, comme Unix, qui permet à ce qu'on dit qu'on veut. Mais
la plupart des systèmes, je crois, utilise des requêtes différentes (qui
n'est pas sans avantages autrement), ce qui fait que quoique on fasse,
cin va attendre. C'était le cas de MS-DOS, par exemple, et il se peut
fort bien que c'est encore le cas de Windows.
| Quote: | e.g., pour un système compatible POSIX :
#include <iostream
#include
int main() {
struct termios tios;
tcgetattr(0, &tios);
tios.c_lflag &= ~(ICANON | ECHO);
tcsetattr(0, TCSANOW, &tios);
using namespace std;
cin.rdbuf()->pubsetbuf(0, 0); // supprime le buffer de cin
|
Et du coup, tu aurais dû inclure <istream> et <streambuf> aussi. (Au
moins selon la norme. Je sais que ce que tu as écris marche à peu près
partout.)
| Quote: | int c;
while(cin) {
c = cin.get();
if(c == EOF) {
cout << endl;
break;
}
cout << "<" << c << "> ";
}
}
ou alors n'utiliser que les fonctions C (<stdio.h>) sur stdin. (je
suppose qu'il y a la même limitation)
|
Tout à fait. Y compris la nécessité de supprimer le bufferisation dans
le flux (setbuf ou setvbuf).
Enfin, pour son operator>>, j'aurais écrit quelque chose du genre :
std::istream&
operator>>( std::istream& source, string& dest )
{
std::istream::sentry guard( source, true ) ;
if ( guard ) {
static size_t const limit = 5 ;
char buffer[ limit + 1 ] ;
char* p = buffer ;
char* end = buffer + limit ;
std::streambuf* sb = source.rdbuf() ;
while ( p != end && sb->sgets() != EOF && sb->sgets() != '*' ) {
*p ++ = sb->sbumps() ;
}
if ( p == buffer ) {
source.setstate( std::ios::failbit ) ;
} else {
dest = string( buffer ) ;
// Je suppose un constructeur adéquat...
}
}
return source ;
}
Mais comme j'ai dit, je ne crois pas que le posteur original en soit là.
Je crois qu'il lui faut les bases des flux d'abord, avant d'aborder les
streambuf (pas que les streambuf soient compliqués en soi, mais chaque
chose dans son temps).
--
James Kanze GABI Software mailto:kanze (AT) gabi-soft (DOT) fr
Conseils en informatique orientée objet/ http://www.gabi-soft.fr
Beratung in objektorientierter Datenverarbeitung
11 rue de Rambouillet, 78460 Chevreuse, France, +33 (0)1 30 23 45 16
|
|