Je n'ai jamais utilisé std::string. Je commence donc, il n'est jamais trop tard ;)
Mais me voici sur un premier soucis, convertir des "valeurs" en string. Bref, je cherche de quoi faire l'équivalent des itoa, sprintf, etc, avec des string.
Merci.
Version imprimable
Je n'ai jamais utilisé std::string. Je commence donc, il n'est jamais trop tard ;)
Mais me voici sur un premier soucis, convertir des "valeurs" en string. Bref, je cherche de quoi faire l'équivalent des itoa, sprintf, etc, avec des string.
Merci.
Bonjour,
La FAQ ?
Oui, merci.
A défaut de mieux je passe parfois par l'intermédiaire des strstream, mais je trouve ça particulièrement lourd et peu élégant. J'en arrive à préfèrer alors ce bon vieux et efficace itoa(), la conversion de 'int' ou 'unsigned' en str étant un cas (très) fréquent. Dans d'autres cas le sprintf() est assez génial pour tout type de présentation des nombres (precision, mantisse, base, etc).
Il n'y a pas d'équivalent en manipulant directement les std::string ? Une classe dérivée avec des méthodes supplémentaires ?
Non mais rien ne t'empêche de te faire des petites fonctions template qui te convertisse n'importe quoi en string, et un string en n'importe quoi. En utilisant les stringstream.Citation:
Il n'y a pas d'équivalent en manipulant directement les std::string ?
Un exemple se trouve ici:
http://farscape.developpez.com/Articles/Conversions/
Il y a boost::lexical_cast qui emballe cette méthode dans un appel de fonction unique.
Merci, je vais regarder un peu tout ça. Et apronfondir les strstream.
Au fait, c'est quoi c++/cli ? Jamais entendu parler...
Salut,
Honnetement, je ne vois pas vraiment ce qu'il y a de "si lourd que cela" à écrire un code proche de
quand on voit les soucis qui peuvent apparaitre avec les fonctions issues du C...Code:
1
2
3
4
5
6
7
8 const std::string convert() { float f = 3.1415926; int i = 5; std::stringstream ss; ss<<"le reel vaut :"<<f<<" et l'entier :"<<i; return ss.str(); }
En plus, l'utilisation de flux de base (istream et ostream) te permet de t'assurer une certaine continuité dans le traitement des classes:
pourrait être, à ton gout, utilisé des manières suivantes:Code:
1
2
3
4
5
6
7
8
9
10 class MaClass { public: MaClass():f(301415926),i(5){} friend class std::ostream& operator<<(std::ostream& ofs, const MaClass& c) { ofs<<"le reel vaut :"<<f<<" et l'entier :"<<i; return ofs; } };
Comme tu l'aura remarqué, l'énorme avantage à l'utilisation des flux de données est *réelement* de fournir une syntaxe identique en tous temps ;)Code:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18 int main() { /* création d'une instance de la classe */ MaClass c; /* affichage sur la sortie standard */ std::cout<<c<<std::end; /* nous aurions pu choisir cerr ou clog, si nous * avions voulu un rapport d'erreur ou un log * d'activités ;-) */ /* ou l'écrire dans un fichier particulier */ std::ofstream ofs("fichier.txt"); ofs<<c<<std::endl; /* et même en arriver à convertir le tout en std::string */ std::stringstream sstr; sstr<<c; std::string s = sstr.str(); return 0; }
OK, convaincu, merci :D
Ce n'est qu'une (bonne) habitude à prendre finalement.
Exactement...
En allant à peine plus loin, et bien que je connaisse le C et que je lui accorde tout le crédit qu'il mérite, je dirais même que la bonne habitude à prendre est de toujours préférer les solutions propres au C++ lorsqu'elles existent à toute alternative issue du C...
A de très rares exceptions près (car il est vrai qu'il n'est pas vraiment évident d'implémenter un algorithme md5 avec les std::string) ce sera de nature à t'apporter facilité et sécurité ;)
Je remonte un peu ce fil car, bien que "facile" et "lisible", l'usage de string et stringstream ne semble pas très performant.
Je me demandais donc si ce code peut rendre la conversion plus rapide:Mais je vous vois déjà hurler d'ici... :lol:Code:
1
2
3 std::string s; s.resize(12); itoa(value,s.begin(),10);
Ou alors quelque chose comme ceci:Je sais ce n'est pas propre.Code:
1
2
3 std::string s; s.resize(12); itoa(value,reinterpret_cast<char *>(s.data()),10);
Mais le but est de demander à std::string d'allouer un certain espace contigu et de le proposer à l'extérieur pour utilisation en écriture (dans l'optique d'éviter des copies multiples).
En marge, je constate que d'une manière générale, l'usage des stream et de string génère du code qui passe plus de temps à allouer et copier des tampon de mémoire qu'au traitement fonctionnel désiré.
Je retire temporairement le caractère résolu de ce fil pour avoir votre avis.
Si j'ai bien compris, le moyen "propre" pour accéder au contenu d'un std::string en écriture est de passer par un iterator. Du coup je ne vois pas d'autre moyen que de réécrire l'algo de conversion, comme ceci par exemple:Ce code me semble sûr et portable car indépendant de l'implémentation de std::string.Code:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21 std::string ul2string(unsigned long value) { char buf[12]; char *bufp=buf; for(;;) { *bufp++=(char)(value % 10u); if ((value/=10u)==0ul) break; } std::string s; s.resize(bufp-buf); std::string::iterator it_s=s.begin(); while (bufp!=buf) { char c=*--bufp; *it_s=(char)(c+'0'); ++it_s; } return s; }
Une alternative est de passer la std::string en paramètre par référence plutôt que de la renvoyer par valeur.
Ce n'est pas une bonne idée. Ne serait-ce que parce que rien ne te garantie la taille d'un unsigned long! Sur 64 bits, ton char[12] :aie:
La bonne solution reste de passer par les stream.
J'avais pensé à ce
char buf[12];
qu'on peut judicieusement remplacer par
char buf[LONG_MAX_DIGITS];
... à condition qu'il existe une macro défine par le compilateur (oui mais en base 10 , 2, 16 ?).
Sinon voici
char buf[sizeof(long)*3];
:P
A vrai dire, ce qui me fait hurler, c'est que tu oublie un principe essentiel:
La première qualité d'un code (j'irais presque jusqu'à dire: avant même que celle qui consiste à faire ce qu'on attend de lui) est donc... d'être facilement lisible par la personne qui l'a devant les yeux ;)Citation:
un code source est plus souvent étudié ou lu que compilé
De plus, je ne le répéterai jamais assez, la solution la plus simple est toujours la moins compliquée... heu... pardon: la meilleure :D
Partant de là, il me semble bien plus cohérent d'avoir recours à... des solutions "simples", et tu avouera que celle qui passe par les flux de conversions est clairement celle qui donne un résultat cohérent en demandant la logique la moins complexe :D
Enfin, il ne faut pas oublier que, tant la classe string que les classes *stringstream sont à la base des classes template (même si elles le cachent bien)...
Cela implique que le compilateur a toutes les latitudes possibles pour apporter des optimisations et fournir quelque chose qui sera - au final - vraisemblablement bien plus optimisé que tout ce que tu pourrais faire de ton coté ;)
Personnellement, il y a trois points qui me chagrinent énormément:
- j'ai horreur de ne pas donner les trois paramètres nécessaires à une boucle "pour"
- L'utilisation de l'instruction break m'horripile s'il y a moyen de faire autrement
- Quitte à ce que cela prenne quelques lignes de code de plus, je préfère respecter la règle du "une ligne, une instruction", et éviter au maximum les effets de bord...
Ce n'est sans doute que pinaillage et "capilotraction", mais j'aurais fortement préféré quelque chose qui prenne une forme proche de
Code:
1
2
3
4
5
6 while(value>0) { *bufp=(char)(value%10); value/=10; bufp++; }
Et voilà comment on change un code correct en un code incorrect, en prétendant le code initial illisible. Permet-moi ainsi de corriger ta correction ;)
Dans le cadre du forum, j'apprécie ton intervention pour corriger le code "illisible", car elle peut m'aider à me débarraser de certaines (mauvaises ?) habitudes. Mais en entreprise, changer le code ancien mais éprouvé d'un vieux singe sous prétexte de lisibilité est passible au mieux d'une prime ou d'une augmentation manquée, au pire de... :aie: Surtout quand le code modifié ne répond plus aux attentes.Code:
1
2
3
4
5
6
7 do { *bufp=(char)(value%10); value/=10; bufp++; } while(value>0);
Cependant, je n'ai pas la réponse à mon interrogation.
Suis-je en droit de mettre en doute le caractère répétitif et non nécessaire des multiples allocations et copies de tampons de mémoire lorsqu'on passe par l'intermédiaire des stringstream ?
Ou bien est-ce que j'écrase et je fais comme il se doit d'être fait sans chercher à faire mieux ? (en appliquant à la lettre le dicton qui dit que "le mieux est l'ennemi du bien").
Effectivement, j'étais un peu fatigué lorsque j'ai écrit le code :aie:
Je te l'accorde, mais, le fait de jouer avec les effet de bords et de faire plusieurs choses à la fois n'est de toutes manières jamais bon ;)Citation:
Dans le cadre du forum, j'apprécie ton intervention pour corriger le code "illisible", car elle peut m'aider à me débarraser de certaines (mauvaises ?) habitudes. Mais en entreprise, changer le code ancien mais éprouvé d'un vieux singe sous prétexte de lisibilité est passible au mieux d'une prime ou d'une augmentation manquée, au pire de... :aie: Surtout quand le code modifié ne répond plus aux attentes.
Et tu as semble-t-il trouvé rapidement le défaut de ma logique ;)
Sauf erreur, les buffers alloués le sont de manière "compensée".... Ce n'est pas parce que tu aurais 20 éléments à placer dans ton buffer que tu auras... 20 allocations et autant de libération de mémoire ;)Citation:
Cependant, je n'ai pas la réponse à mon interrogation.
Suis-je en droit de mettre en doute le caractère répétitif et non nécessaire des multiples allocations et copies de tampons de mémoire lorsqu'on passe par l'intermédiaire des stringstream ?
Ou bien est-ce que j'écrase et je fais comme il se doit d'être fait sans chercher à faire mieux ? (sans oublier que parfois le mieux est l'ennemi du bien).
En outre, je te rappellerais trois principes importants:
Citation:
Dans, mettons, 90% des cas, une optimisation prématurée est la route de toutes les enfers
Citation:
L'exécution passe généralement 80% de son temps dans 20% du code
Citation:
Avant de vouloir gagner quelques cycles d'horloge en cherchant la "meilleur manière d'écrire quelque chose", il est bien plus intéressant de trouver la logique qui permettra d'éviter le maximum d'itération "non nécessaires"
Bref, selon moi, dans un premier temps, il vaut mieux écraser et faire "comme il se doit" (bien que, dans ce cas, j'aurais tendance à plutôt dire "au plus facile" ;))
Si, vraiment, lors du profiling, tu te rend compte que la méthode "simple" demande énormément de temps et / ou de ressources, ta première réaction devrait être de s'interroger sur la complexité des algorithme et de voir s'il n'est pas possible de la diminuer (passer d'une complexité en O(n) à une complexité en O(log(n)), par exemple ou, simplement, t'assurer de l'utilité des chaque conversion ;))
Si l'objectif n'est toujours pas atteint une fois que tu as la certitude que tes algorithme ne font pas plus de conversions que nécessaire et que le profiling t'indique clairement que ce sont les conversions qui sont encore le "goulot d'étranglement", alors, il sera toujours temps de réfléchir à un moyen plus rapide d'effectuer les conversions, et de ne le garder que si le gain est réellement significatif (re-profiling et benchmarks à l'appui ;))
J'aurais pu (du :question:) éditer ma réponse pour y rajouter ce qui suit, mais comme je te propose une autre manière d'envisager les choses, autant te faire une autre réponse ;)
En effet, l'une des solutions envisageables pour éviter au maximum les conversions pourrait être de travailler avec un cache.
Tu déclares une variable de type "chaine de caractères" qui "suit" ta valeur numérique, que tu vide lorsque la valeur numérique change dont tu teste le contenu (vide ou non) avant d'effectuer la conversion.
De cette manière la conversion peut n'être effectuée qu'une fois au lieu de (bien souvent) entre deux modifications de la valeur ;)
Ok, merci merci merci.
Je n'ai donc pas tout à fait tort, sauf peut-être en ce qui concerne le timing: les optimizations se font, éventuellement, en dernier ressort et seulement là où c'est utile.
D'un point de vue strictement technique, j'aimerais savoir si la manière d'utiliser std::string dans l'extrait de code suivant est correcte, universelle et dépourvue d'effets de bord (en fonction du compilo, etc) le but étant d'accéder en écriture au contenu d'un std::string.Code:
1
2
3
4
5
6
7
8
9
10 std::string s; s.resize(bufp-buf); std::string::iterator it_s=s.begin(); while (bufp!=buf) { char c=*--bufp; *it_s=(char)(c+'0'); ++it_s; } return s;
C'est l'idée générale :D
D'autant plus que:
- La S(T)L est malgré tout relativement optimisée
- Le compilateur est souvent en mesure de faire des optimisations bien meilleures que toi, si tu lui permet de comprendre le contexte
- Les optimisation qui se basent sur les effets de bord et autres "sucres syntaxiques" sont généralement très gourmandes en temps de conception, de mise au point, de débuggage et de modification
Il ne sert donc pas à grand chose, si la logique et la conception sont bonnnes, de commencer à perdre du temps à chercher à optimiser des écritures, ou à chercher des méthodes plus complexes que la méthode "la plus simple" si c'est pour gagner trois cycle d'horloge sur une fonction qui n'est appelée qu' exceptionnellement ;)
Tu as un effet de bord à la ligne : char c=*--bufp;Citation:
D'un point de vue strictement technique, j'aimerais savoir si la manière d'utiliser std::string dans l'extrait de code suivant est correcte, universelle et dépourvue d'effets de bord (en fonction du compilo, etc) le but étant d'accéder en écriture au contenu d'un std::string.Code:
1
2
3
4
5
6
7
8
9
10 std::string s; s.resize(bufp-buf); std::string::iterator it_s=s.begin(); while (bufp!=buf) { char c=*--bufp; *it_s=(char)(c+'0'); ++it_s; } return s;
En effet, tu modifie d'un côté l'adresse pointée par un pointeur, et de l'autre, tu assigne ce qui est pointé par ce pointeur à un caractère :aie:
Le risque encouru est qu'une lecture rapide du code fasse que le lecteur "zappe" la décrémentation ;)
Or, cela revient strictement au même que le code
qui montre bien toutes les étapes ;)Code:
1
2char c = *bufp; --bufp;
Pour répondre à ta question de savoir si c'est correct, je dirais qu'il faut se mettre d'accord sur le terme "correct" (par exemple: tu obtiens une chaine inversée par rapport au buffer d'origine, est ce ce que tu souhaite :question:).
Quant à savoir si c'est universel et indépendant du compilo, je dirais que c'est effectivement le cas, vu que tu n'utilise que des types primitifs ou des classes fournie par le standard ;)
Ça n'a rien d'une règle générale... Le code suivant n'utilise que des types standards, mais son résultat dépend du compilateur...
Code:
1
2
3
4
5 int main() { char c=-1; assert(c/2 == 127); }
Dans le cas en question, le c+'0' peut donner des résultats variables en fonction du compilateur, et de la plage de valeur de c.
Je pense que oui. Le plus rapide et le plus sur pour l'accès direct à la string, c'est en effet son itérateur.Citation:
D'un point de vue strictement technique, j'aimerais savoir si la manière d'utiliser std::string dans l'extrait de code suivant est correcte, universelle et dépourvue d'effets de bordCode:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22 std::string ul2string(unsigned long value) { char buf[12]; char *bufp=buf; for(;;) { *bufp++=(char)(value % 10u); if ((value/=10u)==0ul) break; } std::string s; s.resize(bufp-buf); std::string::iterator it_s=s.begin(); while (bufp!=buf) { char c=*--bufp; *it_s=(char)(c+'0'); ++it_s; } return s; }
Il faut juste garder en tête en bossant directement avec les itérateurs que toute modification de la taille de la string peut les invalider. Par exemple, avec visual 2008 :
Dans ce cas, je crois que ça vient du fait que VS alloue les string sur la pile tant qu'elles sont assez légères puis passe sur le tas à partir d'une certaine taille.Code:
1
2
3
4
5
6
7 std::string s; std::string::iterator it = s.begin(); s.resize(5); *it = 'a'; // OK s.resize(100); *it = 'a'; // BOUM, itérateur invalide
Arf... C'est la deuxième fois que je te reprends ;)
Tu veux dire je suppose:*--bufp et *bufp-- c'est pas tout à fait la même chose...Code:
1
2--bufp; char c = *bufp;
Décidément tu n'aimes pas ma manière compact d'écrire du code. Je ne l'ai pas inventé, c'est du C parfaitement valide (et c'était prévu exprès). Je suppose que c'est une habitude qui vient depuis l'époque où (il y a bien longtemps) on nous disait qu'il fallait "aider" le compilo dans ses optimizations.
Je me rappelle d'ailleurs que d'autres en ces temps reculés avaient déjà souligné le manque de lisibilité du code C ainsi compacté, autres à qui on avait finalement rétorqué qu'un bon programmmeur devait pouvoir s'adapter à lire du code ayant pu être écrit par quiconque.
A propos de "correct", je parlais de la manière d'utiliser std::string, en particulier l'accès à son contenu.
Mais Aznar a répondu dans le sens que je supposais/voulais 8-)
Merci !
Perso, je ne ferais jamais ça (assigné un iterator avant un resize). Mais plutôt ceci:Et c'est valable pour tous les itérateurs de la STL en général dès que le taille d'un conteneur est susceptible d'avoir changé.Code:
1
2
3
4
5
6
7 std::string s; s.resize(5); std::string::iterator it = s.begin(); *it = 'a'; // OK s.resize(100); it = s.begin(); *it = 'a'; // plus BOUM, itérateur valide
C'est d'ailleurs une des difficulté de la STL il me semble, connaitre la durée de vie ou la validité d'un itérateur.
Effectivement, je ne nierai pas que j'ai horreur des sucres syntaxiques ;)
Ceci dit, il faut bien te dire que les compilo un tant soit peu récents (mettons simplement ceux sorti depuis la norme C99), ont fait d'énormes progrès en ce qui concerne les optimisations qu'ils sont capables d'apporter...
Ce qui pouvait être vrai il y a une vingtaine d'années (ou plus) ne l'est donc plus maintenant, et c'est tout bénéfice en ce qui concerne les périodes de débuggage et de mise au point ;)
En outre, il faut effectivement se méfier de ce "Et c'est du C valide" car, bien que le C++ hérite du C, on remarque que, les normes évoluant de manière séparée, il est des choses qui sont valides en C mais pas en C++, voire, des fonctions dont il faut adapter l'invocation pour passer de l'un à l'autre (le coup de malloc est assez parlant sur le sujet :D)
Non, je crois bien que arzar a raison. Depuis VS2003 std::string n'alloue sur le tas qu'à partir d'une certaine taille.
D'ailleurs, depuis que je fréquente ce forum (;)) on me fait comprendre que je ne dois pas faire de supposition sur ce que fait ou pas un compilo avec les std::string. On ne doit même pas supposer que la string occupe toujours un espace contigu en mémoire, seul l'appel après c_str() ou data() le garantit.
De manière générale, il ne faut faire aucune supposition sur la manière dont n'importe quel compilateur implémente quoi que ce soit si ce n'est pas explicitement précisé dans la norme...
Et même pour ce qui est explicitement précisé dans la norme, en étant - il faut l'avouer - un tout petit peu paranoïaque, il y a encore lieu de vérifier si le compilateur utilisé (quel qu'il soit encore une fois) la respecte avant de partir du principe que c'est un fait acquis :aie:
En effet, il reste malgré tout relativement rare de trouver un compilateur qui présente une implémentation respectant l'intégralité de la norme, qui - rappelons le - prend malgré tout la forme d'un bouquin de plus de 700 pages, réparties en 27 sections et 5 annexes, et dont il est malgré tout relativement difficile d'avoir une vue d'ensemble... (et je ne parle encore ici que de la norme de 2003 :aie:)
A l'heure actuelle, si l'on peut considérer que la grosse majorité des compilateurs ont fini par implémenter de manière correcte les prescriptions relatives aux principes importants de la norme (même borland semble avoir fait un sérieux effort sur le sujet), il n'est malgré tout pas impossible de rencontrer des parties plus complexes de la norme pour lesquelles un ou l'autre compilateur risque d'éprouver des difficultés à suivre les prescriptions ;)
Et, si l'on considère enfin qu'il y a des comportements dont l'implémentation est soit laissée à l'appréciation de l'éditeur du compilateur, soit purement et simplement non définis dans la norme, cela laisse encore beaucoup de place à l'interprétation personnelle :D
Une sorte de "union" quoi ;)Code:
1
2
3
4
5
6
7
8
9
10 union { char s[...]; struct { char *ptr; size_t len; ... }; };
Dans le mille !
En cherchant "union" dans l'implémentation de la stl de mircrosoft (fichier xstring) on trouve ceci :
(_Elem est un typedef vers char pour les std::string et wchar pour les std::wstring)
Ben c'est sacrement malin quand même. 8OCode:
1
2
3
4
5
6
7
8
9
10
11
12
13 union _Bxty { // storage for small buffer or pointer to larger one _Elem _Buf[_BUF_SIZE]; _Elem *_Ptr; } _Bx; // Avec un peu avant enum { // length of internal buffer, [1, 16] _BUF_SIZE = 16 / sizeof (_Elem) < 1 ? 1 : 16 / sizeof(_Elem)};
Bonjour,
je remonte cette discussion après avoir découvert des choses très intéressantes sur "les nombres dans std::string", lors de mon apnée quotidienne dans le draft du nouveau standart pour le C++0x.
Behold !
Hourra!! :yaisse2:Citation:
Envoyé par Draft standart C++0x
Enfin une forme claire, efficace et lisible pour l'extraction d'un nombre. On n'aura plus à rougir en expliquant qu'il faut utiliser stringstream pour une tache aussi simple.
Deux questions qui me viennent :
1) Pourquoi seulement trois surcharges pour la fonction to_string ? Je suppose que l'idée est de tirer parti d'une conversion implicite vers le type le plus large, mais il est un peu dommage de devoir convertir un innocent float en long double, juste pour avoir un peu moins de fonctions à implémenter, non ?
2) Pourquoi ne pas fournir une version générique dans la foulée ? L'implémentation ne me semble pas très complexe (à part la gestion d'erreur :?) et le résultat pourrait être assez élégant, dans la lignée de boost::lexical_cast<>.
Ne resterait plus qu'à trouver un nom générique catchy. :D Je propose :Code:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19 template <typename T> T from_string(const string& s) { std::istringstream iss(s); // c++0x istringstream peut prendre une const string& dans le constructeur T result; iss >> result; return result; } template <> float from_string(const string& s) { return stof(s); } ... std::string s2 = "3.1415"; float pi = string_to<float>(s2); // appelle stof
T vers string :
string vers T :Code:string to_string<T>(T); // risque de collision ?
Bon là, ça se corse, pourquoi pas :
Code:
1
2
3
4 T sto<T>(const string&); // imite les stoi,stof etc. T string_to<T>(const string&); // plus explicite, reflet de to_string. T from_string<T>(const string&); // symétrie to_string / from_string T extract<T>(const string&); // pas mal aussi.
A vrai dire, stoi, stoul, stol et consort existent déjà...
Le problème est que cela t'oblige à connaitre autant de fonction qu'il n'y a de type, ou peu s'en faut.
C'est là que les stringstream entrent en jeu: un méthode unique permet de travailler avec n'importe quoi, y compris avec des types personnalisés, ce que ne permettent pas les fonctions "classiques".
De ce point de vue, le draft de C++0x ne change, sauf erreur, pas énormément;)
Alors là je râle un peu. Si tu savais que ça existait depuis le début, pourquoi ne pas l'avoir dit plus tôt ?
Je ne trouve pas très - comment dire ? - "pédagogique" de nous embarquer dans les stringstream quand on en a fait le tour, constaté que c'était lourdingue, et qu'on demande explicitement mieux. En ce qui me concerne en tout cas, j'ai un peu dépassé le stade d'afficher des "coucou 523, bonjour 1234.5, hello world" sur la console.
Je vais vérifier dès demain ce que propose le compilo (et à propos, c'est dans quel header #include ?)
Alors, c'est que tu n'a décidément rien compris de ce que l'on essaye de te faire comprendre, à savoir:C'est arguments sont débattus en long, en large et en travers sur le forum, aussi je peux t'assurer que ce sont des points qu'il est vraiment intéressant de garder en tête en permanence (même s'ils sont dans une forme fortement résumée dans cette intervention)
- avant de t'inquiéter d'essayer d'optimiser - en utilisant ta propre méthode - un comportement quelconque, tu dois veiller à optimiser l'algorithme qui l'utilise: les gains en performances seront bien plus importants (il n'y a qu'une fois que tu as la certitude (pour autant qu'on puisse l'avoir) que tu as le meilleur algorithme, et uniquement si tu te rend compte que le comportement en question occasionne un goulot d'étranglement qu'il devient intéressant d'envisager l'optimisation du comportement "standard")
- Un code est sans doute lu plus de cinq fois plus souvent qu'il n'est écrit ou modifié et compilé: la première qualité que l'on demande donc à un code, je dirais presque avant même de respecter l'algorithme et de faire ce qu'on attend de lui, c'est d'être facilement lisible et compréhensible... Outre le fait que les stringstream permettent de convertir n'importe quoi en chaine et inversément, ils présentent en outre l'énorme avantage de présenter une interface sensiblement identique à tout ce qui a trait à la gestion des flux, et donc à permettre bien plus facilement de faire le rapprochement quant au travail effectué
- stoul et consort utilisent des chaines de caractères "C style" dans toute leur splendeur, et bien qu'il est très facile de convertir une std::string en chaine "C style" et inversément, il n'y a pas vraiment de raison de décider de le faire "juste pour le plaisir": Autant utiliser tout ce qui permet de manipuler directement les std::string... Que cela passe par l'utilisation de chaines "C style" et des fonction sto*, ce n'est pour toi qu'un détail d'implémentation, et tu n'a (pour ainsi dire) pas à t'en occuper
- Il faut impérativement se méfier des observations personnelles quant à la représentation qui peuvent être fait des types primitifs... La norme laisse beaucoup trop de liberté aux créateur de compilateurs pour pouvoir partir d'une autre règle que 1 = char <= short <= int <= long <= long long + (unsigned) int = taille suffisante pour représenter l'ensemble des adresses mémoire disponibles: toute autre hypothèse, entre autre basée sur tes observations perso, sur ta machine et avec ton compilateur perso, tend à préparer le moment où tu foncera dans le mur si les conditions (de machine et ou de compilateur) viennent à changer
- Les méthodes issues du C++ sont - de manière quasi systématique - en tut cas bien plus sécurisantes que l'utilisation des méthodes issues du C équivalentes... Or stol et consort font justement partie... de ces méthodes issues du C
Une fois que tu as admis ces quelques points, il devient difficile de dire qu'on est lourd à venir parler en priorité des stringstream's ;)
Maintenat, si tu n'est pas d'accord avec l'un de ces arguments, n'hésite pas à te faire entendre: on peut le justifier de bien des manières ;)
Je crois que tu entretiens un petit malentendu. Qui parle de C-style ?
J'ai réagi à ta réponse à Arzar, réponse que je trouvais un peu condescendante. Arzar parle de C++0x, de nouvelles fonctions qui vont faire partie du C++, des fonctions permettant la conversion directe entre std::string et nombre (ou alors je n'ai pas compris son intervention).
C'est ce que je cherchais depuis le début. Je constate que je ne suis pas le seul à se soucier de ce "manque" puisque les gourous du C++ se proposent d'intégrer enfin ce genre de fonction somme toute élémentaire.
Certes ton discours théorique est juste, quoique académique.
Mais il s'agit ici de partage de connaissance: existe-t-il, oui ou non, des fonctions C++ pour la conversion directe de std::string en nombre et vice & versa ? La réponse semble être "non", pas encore, mais ça va bientôt être "oui".
Il semblait que tu disais à Arzar "je le savais mais je ne voulais pas le dire". Je me trompe peut-être, à toi de confirmer ou infirmer.
Ça me rappelle un peu mon prof d'algorythmique en fac, on y avait vu en détail le tri par tas (heapsort), d'autres algos avaient simplement été mentionnés. A l'examen, celui qui lui écrivait l'algo du quicksort au tableau était busé...
Au boulot, c'est celui qui n'utilise pas quicksort qui est busé.
Tu es un peu comme le prof, tu imposes les "stringstream" par principe autoritaire, pas par efficacité.
En ce qui me concerne, j'ai passé plus de temps à lire et essayer de comprendre les tenants et aboutissant des stream qu'à écrire ma petite fonction qui convertit les std::string en nombre. Et je n'ai pas encore fini l'apprentissage des stream (ils sont assez/trop complexes je trouve). J'ai posé la question autour de moi (des collègues), personne n'utilise ces "machins" (sauf pour faire du log en console). Dur dur de bénéficier de l'expérience de tiers. Donc, en théorie je suis sensé gagner du temps avec les stringstream. En pratique j'en perds...
Certes, on fait beaucoup d'autres choses avec les stream. Et justement, ça ne plait pas, ça ne convient pas et je pense que je vais faire comme beaucoup, ne pas les utiliser finalement.
Si un jour on me pose la question que je posais au début de cette discussion, je donnerais les réponses que je connais. Je n'imposerais pas "la" solution C++ qui consiste à passer par l'intermédiaire des stringstream.
Ainsi, j'ai écrit des fonctions de conversions d'entiers (signé ou non) de et vers les std::string. C'est fait, parce que c'était mon plaisir de le faire, parce que je n'utilise pas le C++ uniquement comme un langage de 4ème ou 5ème génération, parce que finalement c'est simple à faire et qu'on ne perd pas de temps en le faisant. Si quelqu'un veut mon code il suffit de demander. Il devrait être "portable".
En réaction à ton point 2, je crois bien que personne ne lit mon code, pas plus que je ne lis celui des mes collègues. Est-ce une médiocrité spécifique aux gestionnaires de ma boîte de ne pas prévoir la communication et l'échange internes, où est-ce généralisé ?
Je voudrais aussi réagir à ton point 1, mais il y a trop à dire. En substance il n'y a pas qu'une "optimisation" qui intervient éventuellement à la fin du développement. Il y en a plusieurs et elles interviennent à tout moment tout au long du développement. Et la première est d'anticiper dès la conception du projet où seront les goulots d'étranglement.
Bien sûr, ma misérable conversion string/nombre n'aura aucune incidence mesurable sur les performances. Mais il est bon de prendre ce que je pense être une bonne habitude: choisir le meilleur si c'est sans compromis. Et pour moi le meilleur estet non pasCode:string s=i2string(i);
C'est mon avis: le premier code est plus lisible, il est plus performant, et il est plus rapide à taper. J'accepte que tu ne sois pas d'accord, mais laisse-moi le choix.Code:
1
2
3 stringstream ss; ss << i; string s=s.str();