Twitter iPhone pliant OnePlus 11 PS5 Disney+ Orange Livebox Windows 11

[debutant] string

6 réponses
Avatar
pasde.bcausse.spam
bonsoir,

j'ai une methode qui retourne un coordonnée (string) a partir d'un index
(int)

std::string RXMove::index2Coord(int index) {

if(index == PASS)
return "PA";

std::string coord = "";
coord += char((index%9 - 1) + 'A');
coord += char((index/9 - 1) + '1');

return coord;

}

avec des appels

std::string coord = RXMove::index2Coord(10);

cela fonctionne, mais...

1) est'il correcte de creer un objet (sur la pile) et de le retourner a
la fin de la fonction ? (n'est il pas detruit?)

2) n'y a t'il pas multiple copies de nom objet? (au moins une ici
std::string coord = RXMove::index2Coord(10);)

3) return "PA"; est equivalent a return std:string temporaire = "PA"; ?

4) y a t'il une fuite de memoire? quand est detruit
RXMove::index2Coord(10) ?

et enfin comment faut t'il coder cette methode :-)

merci pour votre patience
--
Bruno Causse
http://perso.wanadoo.fr/othello

6 réponses

Avatar
Matthieu Moy
(Bruno Causse) writes:

std::string RXMove::index2Coord(int index) {

if(index == PASS)
return "PA";


Penser a indenter le contenu du if (perso, je mettrais même des
accolades dans ce cas, mais c'est une question de gout).

std::string coord = "";
coord += char((index%9 - 1) + 'A');
coord += char((index/9 - 1) + '1');

return coord;

}

avec des appels

std::string coord = RXMove::index2Coord(10);

cela fonctionne, mais...

1) est'il correcte de creer un objet (sur la pile) et de le retourner a
la fin de la fonction ?


Oui. Par contre, renvoyer un pointeur ou une référence vers cet objet
n'est pas correct.

(n'est il pas detruit?)


A priori, il est copié. Une optimisation autorisée (named return value
je crois) si c'est toujours la même variable qui est retournée (ici,
ce n'est pas le cas) est de créer cette variable directement à
l'endroit où la valeur doit être retournée pour éviter la copie.

2) n'y a t'il pas multiple copies de nom objet? (au moins une ici
std::string coord = RXMove::index2Coord(10);)


Cf. ci-dessus.

3) return "PA"; est equivalent a return std:string temporaire > "PA"; ?


Aux éventuelles recopies près.

4) y a t'il une fuite de memoire? quand est detruit
RXMove::index2Coord(10) ?


Quand le coord de « std::string coord = RXMove::index2Coord(10); » est
détruit, c'est à dire a la fin du bloc de code dans lequel il est
déclaré.

Tant que tu n'utilises pas de pointeurs, tu ne peux pas vraiment avoir
de fuite de mémoire en fait (mais tu peux utiliser des classes qui
utilisent des pointeurs par contre).

--
Matthieu

Avatar
kanze
Bruno Causse wrote:

j'ai une methode qui retourne un coordonnée (string) a partir
d'un index (int)

std::string RXMove::index2Coord(int index) {

if(index == PASS)
return "PA";

std::string coord = "";
coord += char((index%9 - 1) + 'A');


En passant : l'expression ci-dessus a un comportement indéfini,
même s'il marche sur tous les systèmes que j'ai jamais vu. (Les
caractères alpha ne sont pas contigus en EBCDIC, mais les 8
premiers le sont.) La solution « classique », c'est quelque
chose du genre :

coord += "ABCDEFGH"[ index % 9 - 1 ] ;

Je me pose également une question sur le -1. L'opérateur modulo
va donner un résultat entre 0 et 8 compris. -1 fait de -1 à 7.
Indexer avec -1 n'est pas défini non plus.

Si c'est réelement ce que tu veux, j'ajouterais au moins un
assert avant : « assert( index % 9 != 0 ) ». Et même alors, le
code serait plus robuste avec « "?ABCDEFGH"[ index % 9 ] », avec
un renvoie de '?' en cas d'erreur.

coord += char((index/9 - 1) + '1');


Même commentaire pour le -1. Et j'ajouterais aussi un assert
ici, du genre « assert( index < 81 ) », juste pour être sûr.

Question de goût personnel, j'utiliserais aussi la technique
avec le tableau. La contiguïté des codes des chiffres est
garantie par la norme, mais je ne vois pas de raison de faire
différemment pour les chiffres que pour les autres caractères.

return coord;

}

avec des appels

std::string coord = RXMove::index2Coord(10);

cela fonctionne, mais...

1) est'il correcte de creer un objet (sur la pile) et de le
retourner a la fin de la fonction ? (n'est il pas detruit?)


L'objet même est détruit, mais pas avant qu'on en a fait la
copie. C'est la façon « normale » de renvoyer des valeurs.

2) n'y a t'il pas multiple copies de nom objet? (au moins une
ici std::string coord = RXMove::index2Coord(10);)


P't-êt' ben. Formellement, il y a des copies. Mais la norme
autorise explicitement le compilateur de les supprimer, même si
le constructeur de copie a des effets de bord visible.

Il faut dire aussi qu'on copie des chaînes beaucoup dans
certains programmes, au point où on peut s'attendre à ce que
l'implémentation y a fait un peu d'attention aux performances,
pour qu'une copie ne soit pas chère.

Dans l'ensemble, je ne m'en inquièterais pas, sauf si le code
est réelement trop lent, et que le profiler dit que c'est un
problème.

3) return "PA"; est equivalent a return std:string temporaire
= "PA"; ?


return std::string( "PA" ) ;

4) y a t'il une fuite de memoire? quand est detruit
RXMove::index2Coord(10) ?


Quand on a fini avec lui. En fait, à la fin de l'expression
complète où la fonction a été appelée, dans la plupart des cas ;
à la fin de l'initialisation, si l'expression sert à
l'initialisation d'une variable, et si l'expression sert
directement à l'initialisation d'une référence (forcément
const), à la fin de la portée de la référence.

et enfin comment faut t'il coder cette methode :-)


Voir ci-dessus. Sinon :

std::string RXMove::index2Coord(int index)
{
std::ostringstream tmp ;
if ( index == PASS ) {
tmp << "PA" ;
} else {
tmp << "ABCDEFGH"[ index % 9 ]
<< std::dec << index / 9 ;
}
return tmp.str() ;
}

J'avoue que dans ce cas-ci, l'utilisation de stringstream me
semble un peu lourd, mais c'est un bon outil général.

Si on aime le style fonctionnel, on pourrait aussi écrire :

std::string
RXMove::index2Coord(
int index )
{
assert( index == PASS
|| (index >= 9 && index < 81 && index % 9 != 0) ) ;
return index == PASS
? std::string( "PA" )
: ( std::string( 1, "?ABCDEFGH"[ index % 9 ] )
+ std::string( 1, "?12345678"[ index / 9 ] ) ;
}

C'est en fait la forme qui me plaît le plus (et c'est comme ça
que je l'écrirais dans la pratique).

En passant, je crois que j'utiliserai la facteur 10, et non 9.
Ça donne peut-être des valeurs inutilisables, mais pour la mise
au point, c'est beaucoup plus lisible quand tu affiches
simplement la valeur de index comme un chiffre décimal. Et dans
ce cas, pour valider le chiffre, j'utiliserais quelque chose du
genre : « index >= 0 && index < 100 && isLegal[ index ] », ou
isLegal est un bool const[ 100 ] (dont la définition est générée
par un petit programme -- je ne suis pas prêt à tapper des
tableaux comme ça à la main).

--
James Kanze GABI Software
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
kanze
Matthieu Moy wrote:

[...]
Tant que tu n'utilises pas de pointeurs, tu ne peux pas
vraiment avoir de fuite de mémoire en fait (mais tu peux
utiliser des classes qui utilisent des pointeurs par contre).


Tant que tu ne fais pas de new, tu ne peux pas avoir de fuite de
mémoire. Si c'est vrai que l'utilisation de new sans pointeurs
est plutôt rare, quelque chose comme :
Toto& titi = *new Toto ;
est légal. (Il y a bien un pointeur, mais il n'est pas
explicit.)

Tout ça, évidemment, comme tu dis, en supposant que les classes
dont tu te sers n'ont pas de fuite. (Il est quasiment certain
que std::string fait des new dans certains cas. Mais au moins
qu'il y a une erreur dans son implémentation, tu peux en faire
abstraction.)

--
James Kanze GABI Software
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
Bruno CAUSSE
dans l'article ,
à a écrit le 13/05/05 9:17 :

En passant : l'expression ci-dessus a un comportement indéfini,
même s'il marche sur tous les systèmes que j'ai jamais vu. (Les
caractères alpha ne sont pas contigus en EBCDIC, mais les 8
premiers le sont.) La solution « classique », c'est quelque
chose du genre :

coord += "ABCDEFGH"[ index % 9 - 1 ] ;

Je me pose également une question sur le -1. L'opérateur modulo
va donner un résultat entre 0 et 8 compris. -1 fait de -1 à 7.
Indexer avec -1 n'est pas défini non plus.

Si c'est réelement ce que tu veux, j'ajouterais au moins un
assert avant : « assert( index % 9 != 0 ) ». Et même alors, le
code serait plus robuste avec « "?ABCDEFGH"[ index % 9 ] », avec
un renvoie de '?' en cas d'erreur.

coord += char((index/9 - 1) + '1');


Même commentaire pour le -1. Et j'ajouterais aussi un assert
ici, du genre « assert( index < 81 ) », juste pour être sûr.

Question de goût personnel, j'utiliserais aussi la technique
avec le tableau. La contiguïté des codes des chiffres est
garantie par la norme, mais je ne vois pas de raison de faire
différemment pour les chiffres que pour les autres caractères.



static protected String index2Coord(int square) {

if (square == PASS)
return "PS";

int temp = square%9;
StringBuffer coord = new StringBuffer();
coord.append(" ABCDEFGH".charAt(temp));
coord.append((square-temp)/9);
return coord.toString();
}

C'est comme ça que je l'ai codé en java :-)

1) est'il correcte de creer un objet (sur la pile) et de le
retourner a la fin de la fonction ? (n'est il pas detruit?)


L'objet même est détruit, mais pas avant qu'on en a fait la
copie. C'est la façon « normale » de renvoyer des valeurs.

2) n'y a t'il pas multiple copies de nom objet? (au moins une
ici std::string coord = RXMove::index2Coord(10);)


P't-êt' ben. Formellement, il y a des copies. Mais la norme
autorise explicitement le compilateur de les supprimer, même si
le constructeur de copie a des effets de bord visible.

Il faut dire aussi qu'on copie des chaînes beaucoup dans
certains programmes, au point où on peut s'attendre à ce que
l'implémentation y a fait un peu d'attention aux performances,
pour qu'une copie ne soit pas chère.

Dans l'ensemble, je ne m'en inquièterais pas, sauf si le code
est réelement trop lent, et que le profiler dit que c'est un
problème.



Non ce n'est pas un point chaud.

3) return "PA"; est equivalent a return std:string temporaire
= "PA"; ?


return std::string( "PA" ) ;



Ok,

4) y a t'il une fuite de memoire? quand est detruit
RXMove::index2Coord(10) ?


Quand on a fini avec lui. En fait, à la fin de l'expression
complète où la fonction a été appelée, dans la plupart des cas ;
à la fin de l'initialisation, si l'expression sert à
l'initialisation d'une variable, et si l'expression sert
directement à l'initialisation d'une référence (forcément
const), à la fin de la portée de la référence.




Dans mon cas la reference (sans copie) me semble plus adapté

et enfin comment faut t'il coder cette methode :-)


Voir ci-dessus. Sinon :

std::string RXMove::index2Coord(int index)
{
std::ostringstream tmp ;
if ( index == PASS ) {
tmp << "PA" ;
} else {
tmp << "ABCDEFGH"[ index % 9 ]
<< std::dec << index / 9 ;
}
return tmp.str() ;
}

J'avoue que dans ce cas-ci, l'utilisation de stringstream me
semble un peu lourd, mais c'est un bon outil général.

Si on aime le style fonctionnel, on pourrait aussi écrire :

std::string
RXMove::index2Coord(
int index )
{
assert( index == PASS
|| (index >= 9 && index < 81 && index % 9 != 0) ) ;
return index == PASS
? std::string( "PA" )
: ( std::string( 1, "?ABCDEFGH"[ index % 9 ] )
+ std::string( 1, "?12345678"[ index / 9 ] ) ;
}

C'est en fait la forme qui me plaît le plus (et c'est comme ça
que je l'écrirais dans la pratique).


Merci, une info supp,

Existe t'il sur le net une documentation genre API java
Pour les classes standards (normalisées) de C++;

--
Bruno Causse


Avatar
Matthieu Moy
Bruno CAUSSE writes:

Existe t'il sur le net une documentation genre API java
Pour les classes standards (normalisées) de C++;


stl -> google -> j'ai de la chance.

--
Matthieu

Avatar
kanze
Bruno CAUSSE wrote:
dans l'article
,
à a écrit le 13/05/05
9:17 :

static protected String index2Coord(int square) {

if (square == PASS)
return "PS";

int temp = square%9;
StringBuffer coord = new StringBuffer();
coord.append(" ABCDEFGH".charAt(temp));
coord.append((square-temp)/9);
return coord.toString();
}

C'est comme ça que je l'ai codé en java :-)


Pas très joli. Pourquoi cette différence entre le traitement des
deux coordinées. Ce n'est pas très naturel. Et puis, si tu
remplaces « int » par le seul type non-signé en Java, tu as un
comportement tout à fait différent.

La conversion implicite « n'importe quel type » vers chaîne, en
Java, c'est à éviter au maximum. C'est un piège qui ne mène qu'à
du code complétement illisible, et assez fragile.

En fait, à cet égard, j'aimais bien un passage sur la page de
Cay Horstmann (véritable expert et en C++ et en Java) :

The March of Progress

1980: C
printf("%10.2f", x);
1988: C++
cout << setw(10) << setprecision(2) << showpoint << x;
1996: Java
java.text.NumberFormat formatter
= java.text.NumberFormat.getNumberInstance();
formatter.setMinimumFractionDigits(2);
formatter.setMaximumFractionDigits(2);
String s = formatter.format(x);
for (int i = s.length(); i < 10; i++)
System.out.print(' ');
System.out.print(s);

Il paraît qu'il y a du progrès, côté Java, parce que depuis la
première fois que je l'ai vu, il a ajouté :

2004: Java
System.out.printf("%10.2f", x);

Comme quoi, même Java peut faire du progrès. En attendant,
certains d'entre nous n'ont pas attendu autant pour en faire
autant en C++. J'écris :
std::cout << GB_Format( "%10.2f" ).with( x ) ;
depuis au moins dix ans:-). Depuis, Boost aussi a une classe un
peu semblable.

Avec une telle classe, on écrit allègrement :

return square == PASS
? std::string( "PS" )
: GB_Format( "%x%d" )
.with( square % 9 + 10 )
.with( square / 9 )
.asString() ;

Après les vérifications d'usage -- AMHA, le code n'est pas
correct sinon.

Mais vu le problème, je me démande si cette solution n'est pas
un peu lourde.

--
James Kanze GABI Software
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