Edit 2012-04-11
rve tout à fait, à juste titre, a commenté à ce sujet lexical_cast du rendement, de fournir un lien:
http://www.boost.org/doc/libs/1_49_0/doc/html/boost_lexical_cast/performance.html
Je n'ai pas le droit d'accès à dynamiser 1.49, mais je me souviens de rendre mon code plus rapide sur une version plus ancienne. Donc je suppose:
- la réponse suivante est toujours valide (si ce n'est à des fins d'apprentissage)
- il y avait probablement une optimisation introduit quelque part entre les deux versions (je vais rechercher)
- ce qui signifie que boost est toujours de mieux en mieux
Réponse originale à cette question
Juste pour ajouter des informations sur Barry, et Il est d'excellentes réponses:
Certains d'arrière-plan
S'il vous plaît rappelez Boost est écrit par les meilleurs développeurs C++ sur cette planète, et examiné par les mêmes développeurs. Si lexical_cast
a été si mal, quelqu'un aurait piraté la bibliothèque, soit à la critique, ou avec le code.
Je suppose que vous avez manqué le point de lexical_cast
'la réelle valeur...
Comparer des pommes et des oranges.
En Java, vous lancez un sort d'un nombre entier en un Java Chaîne. Vous remarquerez que je ne parle pas d'un tableau de caractères, ou une chaîne définie par l'utilisateur. Vous remarquerez aussi, je ne parle pas de votre définis par l'utilisateur entier. Je parle de la stricte Java Entier et stricte Java Chaîne.
En Python, vous êtes plus ou moins faire la même chose.
Comme dit par d'autres postes, vous sont, en substance, à l'aide de Java et Python équivalents de sprintf
(ou moins standard itoa
).
En C++, vous êtes à l'aide d'un très puissant en fonte. Pas puissant dans le sens de la vitesse brute de performance (si vous voulez de la vitesse, peut - sprintf
"conviendrait mieux), mais puissant dans le sens de l'extensibilité.
Comparer des pommes.
Si vous souhaitez comparer un Java Integer.toString
méthode, alors vous devriez comparer avec C sprintf
ou C++ ostream
des installations.
Le C++ stream solution serait 6 fois plus rapide (sur mon g++) que lexical_cast
, et tout à fait moins extensible:
inline void toString(const int value, std::string & output)
{
// The largest 32-bit integer is 4294967295, that is 10 chars
// On the safe side, add 1 for sign, and 1 for trailing zero
char buffer[12] ;
sprintf(buffer, "%i", value) ;
output = buffer ;
}
Le C sprintf
solution serait 8 fois plus rapide (sur mon g++) que lexical_cast
, mais beaucoup moins sûr:
inline void toString(const int value, char * output)
{
sprintf(output, "%i", value) ;
}
Les deux solutions sont aussi vite ou plus vite que votre solution Java (en fonction de vos données).
Comparer des oranges.
Si vous souhaitez comparer un C++ lexical_cast
, alors vous devriez comparer avec ce pseudo-code Java:
Source s ;
Target t = Target.fromString(Source(s).toString()) ;
La Source et la Cible quel que soit le type que vous voulez, y compris les types intégrés comme boolean
ou int
, ce qui est possible en C++ parce que de modèles.
Extensibilité? C'est qu'un gros mot?
Non, mais elle a un coût connu: Lorsqu'il est écrit par le même codeur, général des solutions à des problèmes spécifiques sont généralement plus lentes que des solutions spécifiques à l'écrit de leurs problèmes spécifiques.
Dans le cas actuel, dans un point de vue naïf, lexical_cast
vont utiliser le flux des installations de convertir d'un type A
dans une chaîne de stream, et puis à partir de cette chaîne de flux dans un type B
.
Cela signifie que tant que votre objet peut être sortie dans un cours d'eau, et d'entrée à partir d'un flux, vous serez en mesure d'utiliser lexical_cast
- dessus, sans toucher une seule ligne de code.
Alors, quelles sont les utilisations de l' lexical_cast
?
Les principales utilisations des lexicale casting sont:
- La facilité d'utilisation (hey, C++ fonte qui fonctionne pour tout être qui a de la valeur!)
- En la combinant avec le modèle lourd de code, où vos types sont paramétrés, et comme vous ne voulez pas avoir affaire avec des détails, et vous ne voulez pas connaître les types.
- Toujours potentiellement relativement efficace, si vous avez un modèle de base de connaissances, comme je vais le démontrer ci-dessous
Le point 2 est très très important ici, car il signifie que nous avons une seule et unique interface/fonction pour lancer une valeur d'un type en une quantité égale ou similaire de la valeur d'un autre type.
C'est le point réel que vous avez manqué, et c'est le point que les coûts en termes de performances.
Mais c'est tellement slooooooowwww!
Si vous voulez premières performances de vitesse, n'oubliez pas que vous avez affaire avec le C++, et que vous avez beaucoup de facilités pour gérer la conversion de manière efficace, et encore, garder l' lexical_cast
facilité d'utilisation de la fonctionnalité.
Il m'a fallu quelques minutes pour regarder le lexical_cast source, et venir avec une solution viable. Ajouter à votre code C++ le code suivant:
#ifdef SPECIALIZE_BOOST_LEXICAL_CAST_FOR_STRING_AND_INT
namespace boost
{
template<>
std::string lexical_cast<std::string, int>(const int &arg)
{
// The largest 32-bit integer is 4294967295, that is 10 chars
// On the safe side, add 1 for sign, and 1 for trailing zero
char buffer[12] ;
sprintf(buffer, "%i", arg) ;
return buffer ;
}
}
#endif
En activant cette spécialisation de lexical_cast pour les cordes et les services de renseignements (par la définition de la macro SPECIALIZE_BOOST_LEXICAL_CAST_FOR_STRING_AND_INT
), mon code est allé 5 fois plus rapide sur mon compilateur g++, ce qui signifie, selon vos données, son rendement devrait être similaire à Java.
Et il m'a fallu 10 minutes de regarder le code boost, et écrire une distance correcte et efficace de la version 32 bits. Et avec un peu de travail, il pourrait sans doute aller plus vite et plus sûr (si l'on a directement accès en écriture à l' std::string
tampon interne, nous pourrions éviter temporaire externe de la mémoire tampon, par exemple).