web-dev-qa-db-fra.com

Comment std :: string est-il implémenté?

Je suis curieux de savoir comment std :: string est implémenté et en quoi diffère-t-il de la chaîne c? Si la norme ne spécifie aucune implémentation, alors toute implémentation avec explication serait formidable avec la façon dont elle satisfait l'exigence de chaîne donnée par la norme?

53
yesraaj

Pratiquement tous les compilateurs que j'ai utilisés fournissent du code source pour le runtime - donc que vous utilisiez GCC ou MSVC ou autre, vous avez la possibilité de regarder l'implémentation. Cependant, une grande partie ou la totalité de std::string sera implémenté en tant que code de modèle, ce qui peut rendre la lecture très difficile.

le livre de Scott Meyer, Effective STL , a un chapitre sur les implémentations std :: string qui est un bon aperçu des variations courantes: "Point 15: Soyez conscient des variations dans les implémentations string".

Il parle de 4 variantes:

  • plusieurs variations sur une implémentation comptée par référence (communément appelée copie en écriture) - lorsqu'un objet chaîne est copié tel quel, le décompte est incrémenté mais les données de chaîne réelles ne le sont pas. Les deux objets pointent vers les mêmes données recomptées jusqu'à ce que l'un des objets les modifie, provoquant une "copie lors de l'écriture" des données. Les variations sont là où des choses comme le refcount, les verrous, etc. sont stockées.

  • une implémentation "short string optimisation" (SSO). Dans cette variante, l'objet contient le pointeur habituel sur les données, la longueur, la taille du tampon alloué dynamiquement, etc. Mais si la chaîne est suffisamment courte, il utilisera cette zone pour contenir la chaîne au lieu d'allouer dynamiquement un tampon

En outre, "C++ plus exceptionnel de Herb Sutter" a une annexe (Annexe A: "Optimisations qui ne le sont pas (dans un monde multithread)") qui explique pourquoi les implémentations recomptées de copie en écriture ont souvent des problèmes de performances dans applications multithread en raison de problèmes de synchronisation. Cet article est également disponible en ligne (mais je ne sais pas si c'est exactement la même chose que ce qui est dans le livre):

Ces deux chapitres mériteraient d'être lus.

73
Michael Burr

std :: string est une classe qui enveloppe une sorte de tampon interne et fournit des méthodes pour manipuler ce tampon.

Une chaîne en C n'est qu'un tableau de caractères

Expliquer toutes les nuances du fonctionnement de std :: string ici prendrait trop de temps. Peut-être jetez un œil au code source de gcc http://gcc.gnu.org pour voir exactement comment ils le font.

12
Glen

Il y a un exemple d'implémentation dans ne réponse sur cette page .

De plus, vous pouvez regarder l'implémentation de gcc, en supposant que gcc soit installé. Sinon, vous pouvez accéder à leur code source via SVN . La plupart de std :: string est implémentée par basic_string , alors commencez par là.

Une autre source possible d'informations est compilateur de Watcom

6
DVK

La solution c ++ pour les chaînes est très différente de la version c. La première différence et la plus importante est que, lorsque le c utilisant la solution ASCIIZ, std :: string et std :: wstring utilisent deux itérateurs (pointeurs) pour stocker la chaîne réelle. L'utilisation de base des classes de chaînes fournit une solution allouée dynamique, donc dans le coût de la surcharge du processeur avec la gestion dynamique de la mémoire, cela rend la gestion des chaînes plus confortable.

Comme vous le savez probablement déjà, le C ne contient aucun type de chaîne générique intégré, ne fournit que quelques opérations de chaîne via la bibliothèque standard. L'une des principales différences entre C et C++ est que le C++ fournit une fonctionnalité encapsulée, il peut donc être considéré comme un type générique falsifié.

En C, vous devez parcourir la chaîne si vous souhaitez en connaître la longueur, la fonction membre std :: string :: size () n'est qu'une instruction (fin - début). Vous pouvez ajouter des chaînes les unes aux autres en toute sécurité tant que vous avez de la mémoire, donc il n'y a pas besoin de s'inquiéter des bogues de dépassement de tampon (et donc des exploits), car l'ajout crée un tampon plus grand si nécessaire.

Comme quelqu'un l'a dit précédemment, la chaîne est dérivée de la fonctionnalité vectorielle, de manière modélisée, ce qui facilite le traitement des systèmes à caractères multi-octets. Vous pouvez définir votre propre type de chaîne en utilisant le typedef std :: basic_string specific_str_t; expression avec n'importe quel type de données arbitraire dans le paramètre de modèle.

Je pense qu'il y a assez d'avantages et de contras des deux côtés:

Chaîne C++ Avantages: - Itération plus rapide dans certains cas (en utilisant définitivement la taille, et il n'a pas besoin des données de la mémoire pour vérifier si vous êtes à la fin de la chaîne, en comparant deux pointeurs. Cela pourrait faire une différence avec le mise en cache) - L'opération de tampon est emballée avec la fonctionnalité de chaîne, donc moins de soucis concernant les problèmes de tampon.

Chaîne C++ Inconvénients: - en raison de l'allocation dynamique de la mémoire, l'utilisation de base peut avoir un impact sur les performances. (heureusement, vous pouvez dire à l'objet chaîne quelle devrait être la taille du tampon d'origine, donc à moins que vous ne la dépassiez, il n'allouera pas de blocs dynamiques à partir de la mémoire) - des noms souvent étranges et incohérents par rapport à d'autres langues. c'est la mauvaise chose à propos de tout ce qui est stl, mais vous pouvez l'utiliser, et cela donne un sentiment ish C++ un peu spécifique. - l'utilisation intensive du modèle force la bibliothèque standard à utiliser des solutions basées sur les en-têtes, ce qui a un impact important sur le temps de compilation.

4
progician

Cela dépend de la bibliothèque standard que vous utilisez.

STLPort par exemple est une implémentation de bibliothèque standard C++ qui implémente des chaînes entre autres choses.

3
Georg Schölly