web-dev-qa-db-fra.com

chaînes immuables vs std :: string

J'ai récemment lu sur les chaînes immuables Pourquoi les chaînes ne peuvent-elles pas être mutables dans Java et .NET? et Pourquoi la chaîne .NET est immuable? ainsi que des informations sur les raisons pour lesquelles D a choisi des chaînes immuables. Il semble y avoir de nombreux avantages.

  • sans danger pour les threads
  • plus sûr
  • plus de mémoire efficace dans la plupart des cas d'utilisation.
  • sous-chaînes bon marché (tokenisation et découpage)

Sans oublier que la plupart des nouveaux langages ont des chaînes immuables, D2.0, Java, C #, Python, etc.

Le C++ bénéficierait-il de chaînes immuables?

Est-il possible d'implémenter une classe de chaîne immuable en c ++ (ou c ++ 0x) qui aurait tous ces avantages?


mise à jour:

Il existe deux tentatives de chaînes immuables const_string et fix_str . Aucun n'a été mis à jour depuis une demi-décennie. Sont-ils même utilisés? Pourquoi const_string n'en a-t-il jamais fait un coup de pouce?

61
deft_code

Comme un avis:

  • Oui, j'aimerais bien une bibliothèque de chaînes immuable pour C++.
  • Non, je ne voudrais pas que std :: string soit immuable.

Vaut-il vraiment la peine de le faire (en tant que fonctionnalité de bibliothèque standard)? Je dirais que non. L'utilisation de const vous donne des chaînes immuables localement, et la nature de base des langages de programmation système signifie que vous avez vraiment besoin de chaînes mutables.

23
anon

J'ai trouvé que la plupart des gens dans ce fil ne comprennent pas vraiment ce que immutable_string est. Il ne s'agit pas seulement de la constance. Le vrai pouvoir de immutable_string est la performance (même dans un programme à un seul thread) et l'utilisation de la mémoire.

Imaginez que, si toutes les chaînes sont immuables et que toutes les chaînes sont implémentées comme

class string {
    char* _head ;
    size_t _len ;
} ;

Comment pouvons-nous implémenter une opération sous-str? Nous n'avons pas besoin de copier de caractères. Tout ce que nous avons à faire est d'attribuer le _head et le _len. Ensuite, la sous-chaîne partage le même segment de mémoire avec la chaîne source.

Bien sûr, nous ne pouvons pas vraiment implémenter une chaîne immuable uniquement avec les deux membres de données. La mise en œuvre réelle peut nécessiter un bloc de mémoire compté par référence (ou pondéré à la volée). Comme ça

class immutable_string {
    boost::fly_weight<std::string> _s ;
    char* _head ;
    size_t _len ;
} ;

La mémoire et les performances seraient meilleures que la chaîne traditionnelle dans la plupart des cas, surtout lorsque vous savez ce que vous faites.

Bien sûr, C++ peut bénéficier d'une chaîne immuable, et c'est bien d'en avoir une. J'ai vérifié le boost::const_string et le fix_str mentionné par Cubbi. Voilà de quoi je parle.

45
yoco

Ma conclusion est que C++ ne nécessite pas le modèle immuable car il a une sémantique constante.

En Java, si vous avez une classe Person et que vous retournez le String name De la personne avec la méthode getName(), votre seule protection est le modèle immuable. Si ce n'est pas le cas, vous devrez clone() vos chaînes toute la nuit et le jour (comme vous devez le faire avec les membres de données qui ne sont pas des objets de valeur typiques, mais qui doivent quand même être protégés).

En C++, vous avez const std::string& getName() const. Vous pouvez donc écrire SomeFunction(person.getName()) où il est comme void SomeFunction(const std::string& subject).

  • Aucune copie n'est arrivée
  • Si quelqu'un veut copier, il est libre de le faire
  • La technique s'applique à tous les types de données, pas seulement aux chaînes
9
Notinlist

Je ne pense pas qu'il y ait de réponse définitive ici. C'est subjectif - sinon à cause des goûts personnels, du moins à cause du type de code que l'on traite le plus souvent. (Pourtant, une question précieuse.)

Les chaînes immuables sont excellentes lorsque la mémoire est bon marché - ce n'était pas vrai lorsque C++ a été développé, et ce n'est pas le cas sur toutes les plateformes ciblées par C++. (OTOH sur des plateformes plus limitées C semble beaucoup plus courant que C++, donc cet argument est faible.)

Vous pouvez créer une classe de chaîne immuable en C++ et la rendre largement compatible avec std::string— mais vous perdrez quand même par rapport à une classe de chaîne intégrée avec des optimisations et des fonctionnalités de langage dédiées.

std::string est la meilleure chaîne standard que nous obtenons, donc je ne voudrais pas voir de problème avec elle. Je l'utilise cependant très rarement; std::string a trop d'inconvénients de mon point de vue.

3
peterchen

Vous n'êtes certainement pas la seule personne à avoir pensé cela. En fait, il y a la bibliothèque const_string de Maxim Yegorushkin, qui semble avoir été écrite en tenant compte de boost. Et voici une petite bibliothèque plus récente, fix_str par Roland Pibinger. Je ne suis pas sûr de la complexité de l'internement de chaînes complètes au moment de l'exécution, mais la plupart des avantages sont réalisables lorsque cela est nécessaire.

3
Cubbi
const std::string

Voilà. Un littéral de chaîne est également immuable, sauf si vous souhaitez adopter un comportement non défini.

Edit: Bien sûr, ce n'est que la moitié de l'histoire. Une variable de chaîne const n'est pas utile car vous ne pouvez pas la faire référencer une nouvelle chaîne. Une référence à une chaîne const le ferait, sauf que C++ ne vous permettra pas de réaffecter une référence comme dans d'autres langages comme Python. La chose la plus proche serait un pointeur intelligent vers une chaîne allouée dynamiquement.

2
Mark Ransom

Les chaînes immuables sont excellentes si, chaque fois qu'il est nécessaire de créer une nouvelle chaîne, le gestionnaire de mémoire sera toujours en mesure de déterminer où se trouve chaque référence de chaîne. Sur la plupart des plates-formes, la prise en charge linguistique d'une telle capacité pourrait être fournie à un coût relativement modeste, mais sur les plates-formes sans prise en charge linguistique intégrée, c'est beaucoup plus difficile.

Si, par exemple, on voulait concevoir une implémentation Pascal sur x86 qui supportait des chaînes immuables, il faudrait que l'allocateur de chaîne puisse parcourir la pile pour trouver toutes les références de chaîne; le seul coût en temps d'exécution nécessiterait une approche cohérente d'appel de fonction [par ex. n'utilisant pas les appels de queue et ayant toutes les fonctions non-feuilles maintiennent un pointeur de trame]. Chaque zone de mémoire allouée avec new devrait avoir un bit pour indiquer si elle contenait des chaînes et celles qui en contiennent devraient avoir un index vers un descripteur de disposition de mémoire, mais ces coûts seraient assez faibles .

Si un GC n'était pas une table pour parcourir la pile, il serait nécessaire que le code utilise des poignées plutôt que des pointeurs et que le code crée des poignées de chaîne lorsque les variables locales entrent dans la portée et détruisent les poignées lorsqu'elles sortent de la portée. Frais généraux beaucoup plus importants.

1
supercat

Qt utilise également des chaînes immuables avec copie sur écriture.
Il y a un débat sur la quantité de performances qu'il vous apporte vraiment avec des compilateurs décents.

0
Martin Beckett

les chaînes constantes n'ont guère de sens avec la sémantique des valeurs, et le partage n'est pas l'une des plus grandes forces de C++ ...

0
fredoverflow