Y at - il une classe modèle standard C ++ Library qui fournit des fonctionnalités de concaténation de chaîne efficace, similaire à C # 's StringBuilder ou Java StringBuffer ?
c++
stl
string-concatenation
An̲̳̳drew
la source
la source
std::ostringstream
.Réponses:
REMARQUE cette réponse a récemment reçu une certaine attention. Je ne préconise pas cela comme une solution (c'est une solution que j'ai vue dans le passé, avant le TSL). Il est une approche intéressante et ne doit être appliqué sur
std::string
oustd::stringstream
si , après votre code de profilage vous découvrez ce fait une amélioration.J'utilise normalement soit
std::string
oustd::stringstream
. Je n'ai jamais eu de problèmes avec ces derniers. Je réserverais normalement de la place d'abord si je connais à l'avance la taille approximative de la corde.J'ai vu d'autres personnes fabriquer leur propre constructeur de cordes optimisé dans un passé lointain.
Il utilise deux chaînes, l'une pour la majorité de la chaîne et l'autre comme zone de scratch pour la concaténation de chaînes courtes. Il optimise les ajouts en regroupant les opérations d'ajout courtes dans une petite chaîne, puis en les ajoutant à la chaîne principale, réduisant ainsi le nombre de réallocations requises sur la chaîne principale à mesure qu'elle s'agrandit.
Je n'ai pas eu besoin de cette astuce avec
std::string
oustd::stringstream
. Je pense qu'il a été utilisé avec une bibliothèque de chaînes tierce avant std :: string, c'était il y a si longtemps. Si vous adoptez une stratégie comme ce profil, votre candidature en premier.la source
scratch
corde accomplisse vraiment quoi que ce soit ici. Le nombre de réallocations de la chaîne principale dépendra en grande partie de sa taille finale et non du nombre d'opérations d'ajout, à moins que l'string
implémentation ne soit vraiment médiocre (c'est-à-dire qu'elle n'utilise pas de croissance exponentielle). Donc, «grouper» leappend
n'aide pas parce qu'une fois que le sousstring
- jacent est grand, il ne se développera qu'occasionnellement de toute façon. En plus de cela, il ajoute un tas d'opérations de copie redondantes et peut plus de réallocations (d'où des appels ànew
/delete
) puisque vous ajoutez à une chaîne courte.str.reserve(1024);
que ce serait plus rapide que cette choseLa manière C ++ serait d'utiliser std :: stringstream ou simplement des concaténations de chaînes simples. Les chaînes C ++ sont modifiables, donc les considérations de performances de la concaténation sont moins préoccupantes.
en ce qui concerne le formatage, vous pouvez faire tout le même formatage sur un flux, mais d'une manière différente, similaire à
cout
. ou vous pouvez utiliser un foncteur fortement typé qui encapsule ceci et fournit une interface de type String.Format, par exemple boost :: formatla source
StringBuilder
existe est de couvrir l'inefficacité du type String de base immuable de Java . En d'autres termes,StringBuilder
c'est du patchwork, nous devrions donc être heureux de ne pas avoir besoin d'une telle classe en C ++.O(n)
en général.La
std::string.append
fonction n'est pas une bonne option car elle n'accepte pas de nombreuses formes de données. Une alternative plus utile consiste à utiliserstd::stringstream
; ainsi:la source
std::string
est l'équivalent C ++: il est mutable.la source
Vous pouvez utiliser .append () pour simplement concaténer des chaînes.
Je pense que vous pourriez même être en mesure de faire:
En ce qui concerne les opérations de formatage des C #
StringBuilder
, je croissnprintf
(ousprintf
si vous voulez risquer d'écrire du code bogué ;-)) dans un tableau de caractères et de reconvertir en chaîne est à peu près la seule option.la source
Étant donné que
std::string
C ++ est modifiable, vous pouvez l'utiliser. Il a+= operator
uneappend
fonction et une fonction.Si vous devez ajouter des données numériques, utilisez les
std::to_string
fonctions.Si vous voulez encore plus de flexibilité sous la forme de pouvoir sérialiser n'importe quel objet en une chaîne, utilisez la
std::stringstream
classe. Mais vous devrez implémenter vos propres fonctions d'opérateur de streaming pour qu'il fonctionne avec vos propres classes personnalisées.la source
std :: string's + = ne fonctionne pas avec const char * (ce que des trucs comme "string to add" semblent être), donc l'utilisation de stringstream est la plus proche de ce qui est requis - vous utilisez simplement << au lieu de +
la source
Un générateur de chaînes pratique pour C ++
Comme beaucoup de gens ont déjà répondu, std :: stringstream est la méthode de choix. Cela fonctionne bien et dispose de nombreuses options de conversion et de formatage. IMO, il a cependant un défaut assez gênant: vous ne pouvez pas l'utiliser comme une seule ligne ou comme une expression. Il faut toujours écrire:
ce qui est assez ennuyeux, surtout lorsque vous souhaitez initialiser des chaînes dans le constructeur.
La raison en est que a) std :: stringstream n'a pas d'opérateur de conversion en std :: string et b) les opérateurs << () du stringstream ne renvoient pas une référence stringstream, mais une référence std :: ostream à la place - qui ne peut pas être davantage calculé comme un flux de chaînes.
La solution est de surcharger std :: stringstream et de lui donner de meilleurs opérateurs correspondants:
Avec cela, vous pouvez écrire des choses comme
même dans le constructeur.
Je dois avouer que je n'ai pas mesuré les performances, car je ne l'ai pas encore utilisé dans un environnement qui utilise beaucoup la construction de chaînes, mais je suppose que ce ne sera pas bien pire que std :: stringstream, puisque tout est fait via des références (sauf la conversion en chaîne, mais c'est également une opération de copie dans std :: stringstream)
la source
std::stringstream
ne se comporte pas de cette façon.Le conteneur Rope peut valoir la peine si vous devez insérer / supprimer une chaîne dans l'emplacement aléatoire de la chaîne de destination ou pour une longue séquence de caractères. Voici un exemple de l'implémentation de SGI:
la source
Je voulais ajouter quelque chose de nouveau pour les raisons suivantes:
Lors d'une première tentative, je n'ai pas réussi à battre
std::ostringstream
deoperator<<
efficacité, mais avec plus d'essais j'ai pu faire un StringBuilder plus rapide dans certains cas.
Chaque fois que j'ajoute une chaîne, je stocke simplement une référence quelque part et augmente le compteur de la taille totale.
La vraie façon dont je l'ai finalement implémenté (Horreur!) Est d'utiliser un tampon opaque (std :: vector <char>):
pour l'octet []
pour les chaînes déplacées (chaînes ajoutées
std::move
)std::string
objet (nous avons la propriété)pour les cordes
std::string
objet (pas de propriété)Il y a aussi une petite optimisation, si la dernière chaîne insérée a été déplacée, elle vérifie les octets libres réservés mais inutilisés et y stocke d'autres octets au lieu d'utiliser le tampon opaque (c'est pour économiser de la mémoire, cela le rend en fait légèrement plus lent , dépend peut-être aussi du CPU, et il est rare de voir de toute façon des chaînes avec un espace réservé supplémentaire)
C'était finalement un peu plus rapide que
std::ostringstream
mais cela a quelques inconvénients:ostringstream
conclusion? utilisation
std::ostringstream
Il corrige déjà le plus gros goulot d'étranglement tout en gagnant quelques points de vitesse avec la mise en œuvre de la mine ne vaut pas les inconvénients.
la source