OVH Cloud OVH Cloud

string et constructeur

23 réponses
Avatar
Nicolas Aunai
bonjour,


comment, dans la liste d'initialisation d'un constructeur, définir la
taille d'une variable string ?


existe-t-il un constructeur pour string qui prendrait la taille en
argument ? je n'en ai aps vu, de plus il semble que :

class A
{
public :
string s;
A();
}

A()
:s(5)
{

}

ne marche pas car le constructeur de string semble vouloir un char *.

j'ai une parade qui consiste a faire :

A()
:s(" ") //'taille' espace
{

}

mais ça sonne un peu "bidouille" a deux euros..

--
Nico,
http://astrosurf.com/nicoastro
messenger : nicolas_aunai@hotmail.com

3 réponses

1 2 3
Avatar
James Kanze
Nicolas Aunai ç writes:

|> "Michaël Monerau" a exposé le 30/11/2003 :

|> > Ouh là ! C'est pas comme ça qu'on doit faire pour extraire
|> > un string d'un flux !

|> > Tu fais tout simplement :

|> > cin >> s;

|> > et tout va bien, jusqu'au prochain espace ou 'enter'. Tu peux
|> > aussi avoir toute une ligne avec les fonctions du style de
|> > getline, etc... Regarde dans les archives du groupe, il y a
|> > déjà eu pas mal de threads à ce sujet (cherche un post de
|> > James particulièrement, où il montrait comment extraire un
|> > int d'un flux, c'est un peu le même principe).

|> euh, excuse mais tu c'est pas pourquoi je fais comme ça :)

|> ça n'a rien a voir avec le c++ mais je vais expliquer ce que je
|> veux faire :

|> j'ai une combinaison de dés et je veux demander a l'utilisateur
|> lesquels relancer, pour celà je lui demdande de taper un X en
|> face du dés a garder, et un '.' en face de celui a relancer, ma
|> chaine ainsi obtenue est convertie en tableau de booléens, et ma
|> fonction 'lancer()' ne relancer que si tab[i] == true...

|> exemple :

|> 5 4 3 1 1
|> . . . X X

Une première question : en mode texte, ou avec une interface
graphique. Parce que ce genre de programme, aujourd'hui, se fait
normalement avec une interface graphique, et des boutons qu'on clique.

En mode texte, ligne à ligne, la solution la plus simple, c'est de
lire une ligne de texte (avec getline) et la parser par la suite. C'est
lorsque tu la parses que tu sautes les blancs, vérifier que les
caractères restants sont ceux auquels tu t'attendais, qu'il n'y en a
pas en trop, etc.

|> converti en booléen : 1 1 1 0 0

|> le cin >> s[i]; me permet de ne pas avoir d'espace dans ma chaine,
|> et donc de garder les mêmes indices de tableaux en tableaux...

Oui. Mais il permettrait aussi d'avoir trop de blancs. Que se
passera-t-il par exemple si l'utilisateur entre un espace à la place
d'un . ?

|> avec un cin >> s; ça me ferait ". . . X X" et non "...XX" ce qui
|> me ferai 4 cases en trop, qu'il faudrai éliminer...

Ou non, selon le cas. Un cin >> s te donnera exactement ".", pour
l'entrée que tu présentes. Par la suite, il faudrait que tu lises
les autres champs. Sans pouvoir savoir quand il y a une nouvelle ligne
(dans les deux cas).

Moi, je commencerais probablement avec un getline. Puis, je
vérifierais la longueur ; éventuellement, je l'étendrais avec
des valeurs par défaut. Par la suite, je crois que tu trouves les
caractères qui t'intéresse aux indices 2*i. Mais je vérifierais
aussi que les autres soient des espaces, à tout hazard.

|> enfin cette idée me semble plus compliquée....

Bof. Les entrées, c'est toujours plus ou moins compliquées. Parce
qu'on ne peut pas compter sur les utilisateurs d'être raisonable.

--
James Kanze mailto:
Conseils en informatique orientée objet/
Beratung in objektorientierter Datenverarbeitung
11 rue de Rambouillet, 78460 Chevreuse, France +33 1 41 89 80 93
Avatar
James Kanze
Michaël Monerau writes:

|> Nicolas Aunai wrote:
|> > "Michaël Monerau" avait soumis l'idée :

|> >> // On prend un std::string avec les espaces en input
|> >> std::string sInput;

|> >> // voir pour cin.getline, je ne me souviens plus exactement
|> >> // les arguments...

|> > là je ne suis pas trop... pourquoi "cin.getline" ? pourquoi pas
|> > cin >> sInput tout simplement ? bon ok je connais pas trop cin et
|> > ses méthodes... pas plus que cout d'ailleurs

|> Si tu fais "cin >> sInput", tu n'auras les caractères que
|> jusqu'au prochain espace... A moins qu'on ne modifie le flag
|> 'skipws' il me semble...

Vue que ses champs sont séparés par les espaces... La plus simple,
ça serait simplement :

std::cin >> c[0] >> c[1] >> c[2] >> c[3] >> c[4] ;

À condition que l'utilisateur a entré exactement ce qu'il
démande, ça doit faire l'affaire.

En connaissant les utilisateurs, en revanche, ce n'est pas le genre de
choses auxquelles j'aime me fier. Personalement, j'écrirais sans
doute quelque chose du genre :

std::string ligne ;
std::getline( std::cin, ligne ) ;
if ( ! std::cin || ligne.size() > 9 ) {
std::cerr << "Mauvais utilisateur, changer l'utilisateurn" ;
exit( 2 ) ;
}
ligne.resize( 9, ' ' ) ;
static GB_RegExpr const
modeleDeLigne( "[.X ] [.X ] [.X ] [.X ] [.X]" ) ;
std::pair< int, std::string::const_iterator >
ok = modeleDeLigne.match( ligne.begin(), ligne.end() ) ;
if ( ok.first == -1 || ok.second() != ligne.end() ) {
std::cerr << "Mauvais utilisateur, changer l'utilisateurn" ;
exit( 2 ) ;
}
for ( int i = 0 ; i < 5 ; i ++ ) {
c[ i ] = ligne[ 2 * i ] == 'X' ;
}

Mais évidemment, j'ai GB_RegExpr dans un tiroir déjà. Sinon,
dans l'industrie, Boost a une classe des expressions rationnelles qui
est encore mieux (plus souple, etc.). Il se peut aussi que je me
renseigne à côté des adaptateurs d'itérateurs de Boost pour
faire un itérateur qui saute de deux en deux, pour pouvoir remplacer
la boucle finale par std::transform. Mais je crais que ça ne
passerait pas très bien dans un oral du DEUG.

Toujours est-il que dans ce cas-ci, c'est assez trivial de remplacer
l'expression rationnelle et la boucle finale par une boucle simple,
piloter par un tableau :

enum ThrowOrNo { throw, keepValue } ;

std::vector< ThrowOrNo >
getInput( std::istream& source )
{
static bool const significant[] = { 0, -1, 1, -1, 2, -1, 3, -1, 4 } ;
static size_t const significantCount
= sizeof( significant ) / sizeof( significant[ 0 ] ) ;
std::string ligne ;
std::getline( source, ligne ) ;
std::vector< ThrowOrNo >
result ;
if ( ! source ) {
throw unexpected_eof() ;
}
if ( ligne.size() > significantCount ) {
throw format_error() ;
}
ligne.resize( significantCount, ' ' ) ;
for ( size_t i = 0 ; i < significantCount ; i ++ ) {
if ( ! significant[ i ] ) {
if ( ligne[ i ] != ' ' ) {
throw format_error() ;
}
} else {
switch ( ligne[ i ] ) {
case 'x' :
case 'X' :
result.push_back( throw ) ;
break ;

case '.' :
case ' ' :
result.push_back( keepValue ) ;
break ;

default :
throw format_error() ;
}
}
}
return result ;
}

Pour du crédit supplémentaire : deux raisons pourquoi je me suis
servi de l'enum ThrowOrNo, plutôt qu'un simple bool ?

--
James Kanze mailto:
Conseils en informatique orientée objet/
Beratung in objektorientierter Datenverarbeitung
11 rue de Rambouillet, 78460 Chevreuse, France +33 1 41 89 80 93
Avatar
James Kanze
DINH Viêt Hoà writes:


|> > Pourquoi faire une telle chose ? L'intérêt de std::string
|> > (en particulier) est justement de ne pas s'occuper de la taille du
|> > string et de faire les opérations dessus, comme ça nous
|> > plaît. Ensuite, c'est lui qui s'occupe de redimensionner tout
|> > ça en dynamique, lorsqu'il y en a besoin...

|> C'est peut-être intéressant de temps en temps de savoir
|> prévoir sa taille afin que la classe string ne passe pas son
|> temps à redimensionner la chaîne , non ?

|> redimensionner la chaîne est souvent coûteux :
|> allocation + copie.

Ça dépend. Dans la pratique, étant donnée la taille des
chaînes en question, et qu'il attend des entrées du clavier, je ne
crois vraiment pas que ça fasse une différence visible.

--
James Kanze mailto:
Conseils en informatique orientée objet/
Beratung in objektorientierter Datenverarbeitung
11 rue de Rambouillet, 78460 Chevreuse, France +33 1 41 89 80 93
1 2 3