C++ équivalent de StringBuffer/StringBuilder?
Est-il C++ Standard Template Library classe qui fournit l'efficacité de concaténation de chaîne de fonctionnalités, similaire à C#'s StringBuilder ou de Java StringBuffer?
- la réponse courte est : Oui, la STL a une classe, et il est
std::ostringstream
.
Vous devez vous connecter pour publier un commentaire.
NOTEZ cette réponse a reçu une certaine attention récemment. Je ne suis pas la promotion de ce qu'une solution (c'est une solution que j'ai vu dans le passé, avant la STL). C'est une approche intéressante et doit être appliquée uniquement sur
std::string
oustd::stringstream
si après avoir établi le profil de votre code, vous découvrez ce qui rend une amélioration.J'ai l'habitude d'utiliser soit
std::string
oustd::stringstream
. Je n'ai jamais eu de problèmes avec ces. Je devrais normalement réserve de certains chambre de première si je sais que la rudesse de la taille de la chaîne à l'avance.J'ai vu d'autres gens faire leur propre optimisé générateur de chaîne dans le passé lointain.
Il utilise deux chaînes pour la majorité de la chaîne et l'autre comme une zone de travail pour concaténer des chaînes courtes. Il optimiser l'ajoute par lots court ajouter des opérations dans un petit string en ajoutant ceci à la chaîne principale, réduisant ainsi le nombre de réaffectations requis sur la chaîne principale est importante, plus.
Je n'ai pas tenu ce truc avec
std::string
oustd::stringstream
. Je pense qu'il a été utilisé avec un tiers de la bibliothèque string avant de std::string, c'était il y a longtemps. Si vous adoptez une stratégie aime ce profil de votre application.scratch
chaîne vraiment accomplit quoi que ce soit ici. Le nombre de réaffectations de la chaîne principale est en grande partie va être fonction de sa taille finale, et non pas le nombre d'ajouter des opérations, à moins que lestring
mise en œuvre est vraiment pauvre (c'est à dire, ne pas utiliser de croissance exponentielle). Donc, "par lot" laappend
n'aide pas, car une fois que le sous-jacentstring
est grand, il ne fera que croître, occasionnellement, de toute façon. Sur le dessus de cela qu'il ajoute un tas de copies redondantes des opérations, et peut plus réaffectations (d'où les appels ànew
/delete
) depuis que vous ajoutez à une courte chaîne.str.reserve(1024);
serait plus rapide que cette choseLe C++ moyen serait d'utiliser std::stringstream ou tout simplement des concaténations de chaîne. Les chaînes C++ sont mutables donc les facteurs de performance de concaténation sont de moins en moins un sujet de préoccupation.
en ce qui concerne le formatage, vous pouvez faire tous la même mise en forme sur un stream, mais d'une manière différente, similaire à
cout
. ou vous pouvez utiliser un typage fort foncteur qui encapsule cette et fournit une Chaîne de caractères.Format comme interface, par exemple, boost::formatStringBuilder
est de couvrir l'inefficacité de Java est immuable de base de type Chaîne de caractères. En d'autres termesStringBuilder
est patchwork, donc nous devrions être heureux que nous n'avons pas besoin d'une telle classe en C++.operator+
. Toutefois, le nouvel objet string est toujours nécessaire d'être créé à l'intérieur deoperator+
pour stocker le résultat de la concaténation de chaîne.O(n)
en général.Le std::string.ajout de la fonction n'est pas une bonne option, car il n'accepte pas de nombreuses formes de données. Plus utile alternative est d'utiliser un std:stringstream, comme suit:
std::string
est le C++ équivalent: C'est mutable.Vous pouvez utiliser .append() pour la simple concaténation de chaînes.
Je pense que vous pourriez même être en mesure de le faire:
Que pour les opérations de mise en forme de C#'s
StringBuilder
, je croissnprintf
(ousprintf
si vous voulez le risque de l'écriture du code bogué 😉 ) dans un tableau de caractères et de les convertir en une chaîne de caractères est la seule option.Depuis
std::string
en C++ est mutable vous pouvez l'utiliser. Il a un+= operator
et unappend
fonction.Si vous avez besoin d'ajouter des données numériques utiliser le
std::to_string
fonctions.Si vous voulez encore plus de flexibilité dans la façon d'être en mesure de serialise n'importe quel objet à une chaîne puis utiliser le
std::stringstream
classe. Mais vous aurez besoin de mettre en œuvre vos propres streaming fonctions de l'exploitant pour qu'il fonctionne avec vos propres classes.std::string += ne fonctionne pas avec const char* (que des trucs comme "chaîne à ajouter" semblent être), donc certainement à l'aide de stringstream est le plus proche de ce qui est nécessaire - il suffit d'utiliser << au lieu de +
Une pratique string builder c++
Comme beaucoup de personnes répondu avant, std::stringstream est la méthode de choix.
Il fonctionne bien et a beaucoup de conversion et les options de formatage. IMO il a une assez gênant défaut cependant: Vous ne pouvez pas l'utiliser comme un liner ou une expression.
Vous devez toujours écrire:
ce qui est assez gênant, surtout quand vous voulez initialiser les chaînes dans le constructeur.
La raison en est, qu'un) std::stringstream n'a pas d'opérateur de conversion de std::string et b) l'opérateur << ()'s de la stringstream ne retourne pas une stringstream de référence, mais un std::ostream référence au lieu - qui ne peut plus être calculée comme une chaîne de stream.
La solution est de remplacer std::stringstream et de lui donner la meilleure correspondance entre les opérateurs:
Avec cela, vous pouvez écrire des choses comme
même dans le constructeur.
Je dois avouer que je n'ai pas à la mesure de la performance, puisque je n'ai pas utilisé dans un environnement qui fait un usage intensif de la chaîne de la construction, mais je suppose qu'il ne sera pas bien pire que std::stringstream, puisque tout se fait via des références (à l'exception de la conversion en chaîne de caractères, mais c'est une opération de copie en std::stringstream ainsi)
La Corde conteneur peut être intéressant si vous avez à insérer/supprimer une chaîne dans l'endroit aléatoire de la chaîne de destination ou pour une longue char séquences.
Voici un exemple de mise en œuvre du SGI:
Je voulais ajouter quelque chose de nouveau pour les raisons suivantes:
À une première tenter je n'ai pas réussi à battre
std::ostringstream
'soperator<<
de l'efficacité, mais avec plus de tentatives j'ai réussi à faire un StringBuilder est plus rapide dans certains cas.
Chaque fois que j'ajoute une chaîne je viens de stocker une référence à quelque part et augmenter le compteur de la taille totale.
Le vrai chemin, j'ai enfin mis en œuvre (l'Horreur!) est d'utiliser un opaque tampon(std::vector < char > ):
pour byte [ ]
déplacé chaînes (chaînes ajoutées avec
std::move
)std::string
objet (nous avons la propriété)pour les chaînes
std::string
objet (pas de droit de propriété)Il y a aussi une petite optimisation, si la dernière inséré chaîne a été mov avait à l', il vérifie gratuit réservé mais les octets non utilisés et de stocker des octets supplémentaires de là, au lieu de l'aide de l'opaque de la mémoire tampon (c'est pour économiser de la mémoire, il en fait, il est un peu plus lent, peut-être dépendent aussi du CPU, et il est rare de voir des chaînes supplémentaires d'espace réservé de toute façon)
C'était finalement un peu plus rapide que
std::ostringstream
mais il a quelques inconvénients:ostringstream
conclusion? utilisation
std::ostringstream
Déjà corrigé le plus gros goulot d'étranglement alors que ganing quelques points de % de la vitesse de la mine de mise en œuvre ne vaut pas les inconvénients.