J'ai fait quelques optimisations nécessaires récemment. Une chose que j'ai faite est de changer certains ostringstreams -> sprintfs. Je sprintf'ing un tas de chaînes std :: strings to ac style array, ala
char foo[500];
sprintf(foo, "%s+%s", str1.c_str(), str2.c_str());
Il s'avère que l'implémentation std :: string :: c_str () de Microsoft s'exécute en temps constant (elle renvoie simplement un pointeur interne). Il semble que libstdc ++ fasse de même . Je me rends compte que le std ne fait aucune garantie pour c_str, mais il est difficile d'imaginer une autre façon de procéder. Si, par exemple, ils copiaient dans la mémoire, ils devaient soit allouer de la mémoire pour un tampon (laissant à l'appelant le soin de le détruire - NE FAIT PAS partie du contrat STL) OU ils devaient copier sur un statique interne tampon (probablement pas threadsafe, et vous n'avez aucune garantie sur sa durée de vie). Donc, le simple retour d'un pointeur vers une chaîne terminée par un null maintenu en interne semble être la seule solution réaliste.
la source
c_str
c'est une méthode const (ou au moins a une surcharge const - j'oublie laquelle), cela ne change pas la valeur logique, donc cela peut être une raisonmutable
. Il serait briser des pointeurs d' autres appels àc_str
, sauf que de tels pointeurs doivent se référer à la même chaîne logique (donc il n'y a pas de nouvelle raison de réallouer - il doit déjà être un terminateur nul) ou bien il doit avoir été un appel à un non -const méthode entre les deux.c_str
appels peuvent être O (n) pour la réallocation et la copie. Mais il est également possible qu'il y ait des règles supplémentaires dans la norme que je ne connais pas qui empêcheraient cela. La raison pour laquelle je le suggère - les appels àc_str
ne sont pas vraiment destinés à être des AFAIK courants, donc il peut ne pas être considéré comme important de s'assurer qu'ils sont rapides - en évitant cet octet supplémentaire de stockage pour un terminateur nul normalement inutile dans lesstring
cas où jamais utiliserc_str
peut ont pris le pas.Boost.Format
passe en interne par des flux qui en internesprintf
finissent par se retrouver avec des frais généraux assez importants. La documentation indique qu'il est environ 8 fois plus lent que ordinairesprintf
. Si vous voulez des performances et une sécurité de type, essayezBoost.Spirit.Karma
.Boost.Spirit.Karma
est un bon conseil pour les performances, mais sachez qu'il a une méthodologie très différente qui peut être difficile à adapter leprintf
code de style existant (et les codeurs). Je suis en grande partie resté avecBoost.Format
parce que nos E / S sont asynchrones; mais un facteur important est que je peux convaincre mes collègues de l'utiliser de manière cohérente (permet toujours à n'importe quel type avec uneostream<<
surcharge - ce qui joliment dérive le.c_str()
débat) Les chiffres de performance du Karma .Dans la norme c ++ 11 (je lis la version N 3290), le chapitre 21.4.7.1 parle de la méthode c_str ():
const charT* c_str() const noexcept; const charT* data() const noexcept;
Alors oui: la complexité à temps constant est garantie par la norme.
Je viens de vérifier la norme c ++ 03, et elle n'a pas de telles exigences, ni ne dit la complexité.
la source
En théorie, C ++ 03 n'exige pas cela, et donc la chaîne peut être un tableau de caractères où la présence du terminateur nul est ajoutée juste au moment où c_str () est appelée. Cela peut nécessiter une réallocation (cela ne viole pas la constance, si le pointeur privé interne est déclaré comme
mutable
).C ++ 11 est plus strict: il nécessite du temps, donc aucune relocalisation ne peut être effectuée et le tableau doit toujours être suffisamment large pour stocker le null à la fin. c_str (), en soi, peut encore faire "
ptr[size()]='\0'
" pour s'assurer que le null est bien présent. Il ne viole pas la constance du tableau puisque la plage[0..size())
n'est pas modifiée.la source