Pourquoi y a-t-il autant de classes de chaînes face à std :: string?

56

Il me semble que beaucoup de bibliothèques C ++ plus grandes finissent par créer leur propre type de chaîne. Dans le code client que vous avez soit d'utiliser celui de la bibliothèque ( QString, CString, fbstringetc., je suis sûr que tout le monde peut en nommer que quelques - uns) ou garder la conversion entre le type standard et celui des usages bibliothèque (qui la plupart du temps implique au moins une copie).

Alors, y a-t-il un problème particulier ou une anomalie std::string(tout comme la auto_ptrsémantique était mauvaise)? At-il changé en C ++ 11?

Tamás Szelei
la source
32
Cela s'appelle "le syndrome non inventé ici".
Cat Plus Plus
10
@CatPlusPlus QString et CString étaient tous les deux antérieurs à std :: string.
Gort le robot
8
@ Chat Plus Plus: Ce syndrome ne semble pas affecter la classe Java String.
Giorgio
20
@Giorgio: Les programmeurs Java sont trop occupés à inventer des solutions de contournement du langage pour se soucier des classes de chaînes (Android réinventé, d'ailleurs).
Cat Plus Plus
9
@Giorgio: C'est probablement parce que le support syntaxique codé en dur de Java pour java.lang.String(manque de surcharge d'opérateur, etc.) rendrait difficile l'utilisation de tout autre chose.
Escargot mécanique

Réponses:

57

La plupart de ces plus grandes bibliothèques C ++ ont été démarrées avant d' std::stringêtre normalisées. D'autres incluent des fonctionnalités supplémentaires qui ont été normalisées tardivement, ou ne sont toujours pas normalisées, telles que la prise en charge de UTF-8 et la conversion entre les codages.

Si ces bibliothèques étaient mises en œuvre aujourd'hui, elles choisiraient probablement d'écrire des fonctions et des itérateurs fonctionnant sur des std::stringinstances.

Ben Voigt
la source
5
La prise en charge de UTF-8 est normalisée depuis C ++ 98. D'une manière peu pratique et partiellement définie par l'implémentation, personne ne semble pouvoir l'utiliser
AProgrammer
9
@AProgrammer: charest garanti d'être assez grand pour contenir n'importe quel point de code UTF-8. Autant que je sache, c'est le seul "support" fourni par C ++ 98.
Ben Voigt
4
@AProgrammer: Ce support est vraiment inutile.
DeadMG
4
@AProgrammer On peut soutenir que ces paramètres régionaux sont brisés, car ils newchar_t sont pas assez grands pour représenter tous les points de code Unicode. De plus, il y a eu toute cette discussion sur UTF-16 considérée comme préjudiciable lorsque l'argument très convaincant a été avancé selon lequel l' UTF-8 devrait être utilisé exclusivement
Konrad Rudolph le
6
@ KonradRudolph, ce n'est pas le système de paramètres régionaux qui est cassé ici (la définition de wchar_t est "suffisamment large pour tout jeu de caractères pris en charge"); les systèmes ayant validé un fichier wchar_t 16 bits se sont engagés en même temps à ne pas prendre en charge Unicode. Eh bien, le coupable est Unicode qui a tout d’abord garanti qu’il n’utiliserait jamais de points de code nécessitant plus de 16 bits, puis les systèmes s’engageant sur un wchar_t 16 bits, puis la commutation unicode nécessitant plus de 16 bits.
AProgrammer
39

String est le gros embarras de C ++.

Pendant les 15 premières années, vous ne fournissez pas de classe de chaîne, ce qui oblige chaque compilateur de chaque plate-forme et chaque utilisateur à créer le leur.

Ensuite, vous créez quelque chose de confus quant à savoir si elle est supposée être une API de manipulation de chaîne complète ou juste un conteneur de caractères STL, avec certains algorithmes qui dupliquent ceux qui sont sur un std :: Vector ou qui sont différents.

Où une opération de chaîne évidente telle que replace () ou mid () implique un tel amalgame d'itérateurs qu'il est nécessaire d'introduire un nouveau mot clé "auto" pour que l'instruction soit correcte sur une seule page et conduit la plupart des gens à abandonner la totalité du langage .

Et puis vous avez unicode 'support' et std :: wstring qui est juste arghh .....

<rant off> merci - je me sens beaucoup mieux maintenant.

Martin Beckett
la source
12
@DeadMG - oui, il a été normalisé en 1998, 15 ans après son invention et 6 ans après, même MSFT, l’utilisait. Oui, les itérateurs sont un moyen utile de rendre un tableau et une liste identiques, pensez-vous qu'ils sont un moyen évident de manipuler des chaînes?
Martin Beckett
3
C with Classes a été inventé en 1983. Pas C ++. Les seules bibliothèques Standard sont celles déterminées par Standard - ce qui est assez étrange, ne peut se produire que si vous avez un Standard, donc la date la plus proche possible pour n'importe quelle bibliothèque Standard est 1998. Les itérateurs peuvent être considérés exactement égaux aux index, mais fortement typés. Je suis tout à fait pour le fait que les itérateurs sont nuls par rapport aux gammes, mais ce n'est pas vraiment spécifique std::string. L'absence d'une classe de cordes en 1983 ne justifie pas d'en avoir plus maintenant.
DeadMG
8
Je pensais que les iostreams étaient le gros embarras de C ++ ...
Doug T.
18
@DeadMG Les gens utilisaient quelque chose appelé "C ++" pendant de nombreuses années avant 1998. J'ai écrit mon premier programme utilisant quelque chose appelé "C ++" en 1985. Si vous voulez dire que ce n'est pas du "vrai" C ++, c'est très bien, mais avant cela, nous écrivions du code et devions obtenir une classe de chaînes quelque part. Une fois que nous avions ces anciennes bases de code, nous ne pouvions pas les supprimer ou les réécrire à partir de zéro quand nous avions une norme. Maintenant, ce qui aurait dû arriver est qu’il aurait dû y avoir une classe de chaînes fournie avec cfront.
Gort le robot
8
@DeadMG - Si personne n'utilisait une langue avant d'avoir obtenu la certification ISO, aucune langue ne serait jamais utilisée puisqu'elle n'atteindrait jamais l'ISO. Il n'y a pas de norme ISO pour l'assembleur x86 mais je suis heureux d'utiliser la plate
Martin Beckett
32

En fait ... il y a plusieurs problèmes avec std::string, et oui, la situation s'améliore un peu en C ++ 11, mais il ne faut pas prendre de vitesse.

QStringet CStringfont partie d’ anciennes bibliothèques, elles existaient donc avant la normalisation du C ++ (un peu comme le SGL STL). Ils ont donc créer une classe.

fbstringrépondre à des problèmes de performance très spécifiques. La norme prescrit une interface et une complexité algorithmique garantissant des minima. Il s'agit toutefois d'un détail de qualité d'implémentation, que cela soit rapide ou non. fbstringa des optimisations spécifiques (liées au stockage, ou plus rapide findpar exemple).

Autres préoccupations qui n'ont pas été évoquées ici (en vrac):

  • en C ++ 03, il n'est pas obligatoire que le stockage soit contigu, ce qui rend potentiellement difficile l'interopérabilité avec C. C ++ 11 corrige cela.
  • std::string codage ignorant et n'ayant pas de code spécial pour UTF-8, il est facile de stocker une chaîne UTF-8 et de la corrompre par inadvertance
  • std::stringl’interface est surchargée , de nombreuses méthodes auraient pu être implémentées en tant que fonctions libres et beaucoup sont dupliquées pour se conformer à la fois à une interface basée sur un index et à une interface basée sur un itérateur.
Matthieu M.
la source
5
Objet n ° 1 - C ++ 03 21.3.6 / 1 garantit le c_str()renvoi d'un pointeur sur la mémoire contiguë, ce qui permet une certaine interopérabilité du C. Cependant, vous ne pouvez pas modifier les données pointées. Les solutions de contournement typiques incluent l’utilisation de vector<char>.
John Dibling
@JohnDibling: Oui, et il y a une autre limitation: il peut en résulter une copie dans le stockage nouvellement alloué (la norme ne dit pas qu'elle ne le fera pas). Bien sûr, C ++ 11 n'empêche pas la copie non plus, mais comme vous pouvez simplement le faire, &s[0]cela n'a plus d'importance :)
Matthieu M.
1
@MatthieuM .: Le pointeur obtenu via &s[0]ne peut pas pointer vers une chaîne terminée par NUL (à moins d' c_str()avoir été appelé depuis la dernière modification).
Ben Voigt
2
@ Mattthieu: Un autre tampon n'est pas autorisé. " c_str()Retour: Un pointeur ptel que p + i == &operator[](i)pour chaque ientrée [0,size()]".
Ben Voigt
3
Il convient également de noter que plus personne de droit n'utilise MFC, il est donc difficile d'affirmer que CString est une classe de chaînes en C ++ moderne.
DeadMG
7

Outre les raisons affichées ici, il en existe un autre - la compatibilité binaire . Les rédacteurs des bibliothèques n’ont aucun contrôle sur l’ std::stringimplémentation que vous utilisez ni sur le fait qu’elle possède la même structure de mémoire que la leur.

std::stringest un modèle, sa mise en œuvre provient donc de vos en-têtes STL locaux. Maintenant, imaginez que vous utilisiez localement une version STL optimisée pour les performances, entièrement compatible avec le standard. Par exemple, vous avez peut-être choisi d’introduire des tampons statiques dans chacun std::stringd’ eux pour réduire le nombre d’allocations dynamiques et d’absence de mémoire cache. En conséquence, la disposition de la mémoire et / ou la taille de votre implémentation sont différentes de celles de la bibliothèque.

Si seule la présentation est différente, certains std::stringappels de fonction de membre sur des instances passées de la bibliothèque au client ou l'inverse peut échouer, en fonction des membres déplacés.

Si la taille est également différente, tous les types de bibliothèque ayant un std::stringmembre auront une taille différente quand ils sont cochés dans la bibliothèque et dans le code client. Les std::stringdécalages des membres de données suivants seront également décalés, et tout accesseur en accès direct / en ligne appelé à partir du client retournera des ordures, malgré le "bon résultat" lors du débogage de la bibliothèque elle-même.

Bottomline - Si la bibliothèque et le code client sont compilés par des std::stringversions différentes , ils seront parfaitement liés , mais cela peut donner lieu à des bogues méchants et difficiles à comprendre. Si vous modifiez votre std::stringimplémentation, toutes les bibliothèques exposant des membres de STL doivent être recompilées pour correspondre à la std::stringprésentation du client . Et parce que les programmeurs veulent que leurs bibliothèques soient robustes, vous ne les verrez que rarement std::stringexposés.

Pour être juste, cela s'applique à tous les types de LIST. IIRC ils n'ont pas la disposition de mémoire standardisée.

Gwiazdorrr
la source
2
Vous devez être un programmeur * nix. La compatibilité binaire C ++ n’est pas identique sur toutes les plates-formes, et plus précisément sous Windows, les classes contenant des données membres ne sont pas portables entre les compilateurs.
Ben Voigt
(Je veux dire sauf les types de POD, et même alors, des exigences d'emballage explicites sont nécessaires)
Ben Voigt
1
Merci pour la contribution, bien que je ne parle pas de compilateur différent, je parle de STL différent.
Gwiazdorrr
1
+1: ABI est une excellente raison de lancer votre propre version d'une classe fournie par le compilateur. Pour cela seulement, j'aimerais que ce soit la réponse acceptée.
Thomas Eding
6

Il y a beaucoup de réponses à la question mais en voici quelques unes:

  1. Héritage. De nombreuses bibliothèques et classes de chaînes ont été écrites AVANT l’existence de std :: string.

  2. Pour la compatibilité avec le code en C. La bibliothèque std :: string est en C ++, car il existe d’autres bibliothèques de chaînes qui fonctionnent avec C et C ++.

  3. Pour éviter les allocations dynamiques. La bibliothèque std :: string utilise l'allocation dynamique et peut ne pas convenir aux systèmes intégrés, au code d'interruption ou en temps réel ou aux fonctionnalités de bas niveau.

  4. Modèles. La bibliothèque std :: string est basée sur des modèles. Jusqu'à récemment, un certain nombre de compilateurs C ++ avaient un support de gabarit peu performant ou même bogué. Malheureusement, je travaille dans un secteur qui utilise de nombreux outils personnalisés et l'une de nos chaînes d'outils d'un acteur majeur du secteur ne supporte pas "officiellement" le C ++ (avec des bugs comme modèles, etc.).

Il y a probablement beaucoup d'autres raisons valables aussi.

Adisak
la source
2
"Assez récemment", ce qui signifie "Cela fait une décennie que même Visual Studio ne les supportait pas assez"?
DeadMG
@DeadMG - Visual Studio n'est pas le seul compilateur non conforme au monde. Je travaille dans les jeux vidéo et nous travaillons souvent sur des compilateurs personnalisés pour des plates-formes matérielles non publiées (cela se produit toutes les quelques années dans les cycles de la console ou lorsqu'un nouveau matériel apparaît). "Assez récemment" signifie aujourd'hui - À l'heure actuelle, certains compilateurs ne prennent pas bien en charge les modèles. Je ne peux pas être spécifique sans violer les NDA, mais je travaille actuellement sur une plate-forme avec des chaînes d'outils personnalisées où la prise en charge de C ++, en particulier la conformité des modèles, est considérée comme "expérimentale".
Adisak
4

Cela concerne principalement Unicode. La prise en charge standard pour Unicode est au mieux catastrophique et chacun a ses propres besoins en Unicode. Par exemple, ICU prend en charge toutes les fonctionnalités Unicode que vous pourriez souhaiter, derrière l’interface Java la plus dégoûtante que vous puissiez imaginer, et si vous êtes sur Unix coincé avec UTF-16, votre idée de un bon moment.

En outre, de nombreuses personnes ont besoin de différents niveaux de prise en charge Unicode. Tout le monde n'a pas besoin des API de mise en page de texte complexes, etc. Il est donc facile de comprendre pourquoi de nombreuses classes de chaînes existent. La classe Standard est vraiment nul et tout le monde a des besoins différents des nôtres, personne ne parvenant à créer une seule classe pouvant exécuter de nombreuses fonctions de support Unicode sur plusieurs plates-formes avec une interface agréable.

A mon avis, c'est principalement la faute du Comité C ++ pour ne pas fournir correctement le support pour Unicode - en 1998 ou 2003, c'était peut - être compréhensible, mais pas en C ++ 11. Espérons qu'en C ++ 17, ils feront mieux.

DeadMG
la source
Bonjour, C ++ 20 ici, devinez ce qui est arrivé au support Unicode?
Passer le
-4

C'est parce que chaque programmeur a quelque chose à prouver et qu'il ressent le besoin de créer sa propre classe de cordes impressionnante et plus rapide pour sa fonction géniale. C'est généralement un peu superflu et conduit à toutes sortes de conversions de chaînes supplémentaires dans mon expérience.

Chad Stewart
la source
7
Si cela était vrai, je m'attendrais à voir un nombre similaire d'implémentations de chaînes dans des langages tels que Java, où une bonne implémentation a toujours été disponible.
Bill K
@ BillK la chaîne Java est finale, vous devez donc mettre de nouvelles fonctionnalités ailleurs.
Et ce que je veux dire, c'est que même en étant final, en 20 ans, je n'ai jamais vu personne écrire une accélération de chaîne personnalisée (eh bien, je voulais essayer d'améliorer les performances de concaténation de chaînes, mais il s'avère que java est BEAUCOUP plus intelligent en chaîne + chaîne que vous ' d imagine)
Bill K
2
@ Bill: Cela pourrait être dû à une culture différente. C ++ attire ceux qui veulent comprendre les détails de bas niveau. Java attire ceux qui veulent juste faire le travail en utilisant les blocs de construction de quelqu'un d'autre. (Notez qu'il ne s'agit pas d'une affirmation à propos d'un individu en particulier qui choisit d'utiliser l'une ou l'autre langue, mais à propos des objectifs de conception et de la culture de chaque langue.)
Ben Voigt