web-dev-qa-db-fra.com

char * vs std :: string en c ++

Quand dois-je utiliser std::string et quand dois-je utiliser char* pour gérer les tableaux de chars en C++?

Il semble que vous devriez utiliser char* si les performances (vitesse) sont cruciales et que vous êtes prêt à accepter certaines activités risquées en raison de la gestion de la mémoire.

Y a-t-il d'autres scénarios à considérer?

78
anon

Vous pouvez passer std :: strings par référence si elles sont grandes pour éviter la copie, ou un pointeur vers l'instance, donc je ne vois aucun avantage réel à utiliser des pointeurs char.

J'utilise std :: string/wstring pour plus ou moins tout ce qui est du texte réel. char * est cependant utile pour d'autres types de données et vous pouvez être sûr qu'elles seront désallouées comme il se doit. Sinon, std :: vector est la voie à suivre.

Il y a probablement des exceptions à tout cela.

55
Skurmedel

Mon point de vue est:

  • N'utilisez jamais char * si vous n'appelez pas le code "C".
  • Utilisez toujours std :: string: c'est plus facile, c'est plus convivial, c'est optimisé, c'est standard, ça vous évitera d'avoir des bugs, ça a été vérifié et ça a fait ses preuves.
54
Gal Goldman

Utilisation de chaînes brutes

Oui, parfois vous pouvez vraiment faire ça. Lorsque vous utilisez const char *, les tableaux char alloués sur la pile et les littéraux de chaîne, vous pouvez le faire de manière à ce qu'il n'y ait aucune allocation de mémoire du tout.

L'écriture d'un tel code nécessite souvent plus de réflexion et d'attention que l'utilisation d'une chaîne ou d'un vecteur, mais avec des techniques appropriées, cela peut être fait. Avec des techniques appropriées, le code peut être sûr, mais vous devez toujours vous assurer que lors de la copie dans char [], vous avez soit des garanties sur la longueur de la chaîne copiée, soit vous vérifiez et gérez les chaînes surdimensionnées avec élégance. Ne pas le faire est ce qui a donné à la famille de fonctions strcpy la réputation d'être dangereuse.

Comment les modèles peuvent aider à écrire des tampons de caractères sécurisés

En ce qui concerne la sécurité des tampons char [], les modèles peuvent aider, car ils peuvent créer une encapsulation pour gérer la taille du tampon pour vous. Des modèles comme celui-ci sont mis en œuvre, par exemple par Microsoft pour fournir des remplacements sûrs pour strcpy. L'exemple ici est extrait de mon propre code, le vrai code a beaucoup plus de méthodes, mais cela devrait suffire pour transmettre l'idée de base:

template <int Size>
class BString
{
  char _data[Size];

  public:
  BString()
  {
    _data[0]=0;
    // note: last character will always stay zero
    // if not, overflow occurred
    // all constructors should contain last element initialization
    // so that it can be verified during destruction
    _data[Size-1]=0;
  }
  const BString &operator = (const char *src)
  {
    strncpy(_data,src,Size-1);
    return *this;
  }

  operator const char *() const {return _data;}
};

//! overloads that make conversion of C code easier 
template <int Size>
inline const BString<Size> & strcpy(BString<Size> &dst, const char *src)
{
  return dst = src;
}
13
Suma

Une occasion que vous DEVEZ utiliser char* et pas std::string est lorsque vous avez besoin de constantes de chaîne statiques. La raison en est que vous n'avez aucun contrôle sur les modules de commande qui initialisent leurs variables statiques, et un autre objet global d'un module différent peut faire référence à votre chaîne avant son initialisation. http://google-styleguide.googlecode.com/svn/trunk/cppguide.xml#Static_and_Global_Variables

std::string avantages:

  • gère la mémoire pour vous (la chaîne peut augmenter et l'implémentation vous allouera un tampon plus grand)
  • Interface de programmation de niveau supérieur, fonctionne bien avec le reste de STL.

std::string inconvénients: - deux instances de chaîne STL distinctes ne peuvent pas partager le même tampon sous-jacent. Donc, si vous passez par valeur, vous obtenez toujours une nouvelle copie. - il y a une pénalité de performance, mais je dirais que si vos exigences ne sont pas spéciales, elle est négligeable.

9
thesamet

Vous devriez envisager d'utiliser char* dans les cas suivants:

  • Ce tableau sera passé en paramètre.
  • Vous connaissez à l'avance la taille maximale de votre tableau (vous le savez OR vous l'imposez).
  • Vous ne ferez aucune transformation sur ce tableau.

En fait, en C++, char* sont souvent utilisés pour les petits mots fixes, comme options, nom de fichier, etc ...

8
Jérôme

Quand utiliser une chaîne std :: c ++:

  • les chaînes, dans l'ensemble, sont plus sécurisées que char *, normalement lorsque vous faites des choses avec char *, vous devez vérifier les choses pour vous assurer que tout va bien, dans la classe des chaînes, tout cela est fait pour vous.
  • Habituellement, lorsque vous utilisez char *, vous devrez libérer la mémoire que vous avez allouée, vous n'avez pas à le faire avec de la chaîne car il libérera son tampon interne lorsqu'il sera détruit.
  • Les chaînes fonctionnent bien avec c ++ stringstream, formaté IO est très facile.

Quand utiliser char *

  • L'utilisation de char * vous donne plus de contrôle sur ce qui se passe "en coulisses", ce qui signifie que vous pouvez régler les performances si vous en avez besoin.
5
user88637

Utilisez (const) char * comme paramètres si vous écrivez une bibliothèque. Les implémentations std :: string diffèrent entre les différents compilateurs.

3
Nemanja Trifunovic

Si vous souhaitez utiliser des bibliothèques C, vous devrez vous occuper des chaînes C. Il en va de même si vous souhaitez exposer votre API à C.

2
n0rd

Vous pouvez vous attendre à ce que la plupart des opérations sur une chaîne std :: (comme par exemple find) soient aussi optimisées que possible, elles sont donc susceptibles d'effectuer au moins aussi bien qu'un homologue C pur.

Il convient également de noter que les itérateurs std :: string sont souvent mappés vers des pointeurs dans le tableau de caractères sous-jacent. Ainsi, tout algorithme que vous concevez au-dessus des itérateurs est essentiellement identique au même algorithme au-dessus de char * en termes de performances.

Les choses à surveiller sont par exemple operator[] - la plupart des implémentations STL n'effectuent pas de vérification des limites et doivent traduire cela en la même opération sur le tableau de caractères sous-jacent. AFAIK STLPort peut éventuellement effectuer une vérification des limites, auquel cas cet opérateur serait un peu plus lent.

Alors, que vous apporte std :: string? Il vous dispense de la gestion manuelle de la mémoire; le redimensionnement du tableau devient plus facile, et vous devez généralement penser moins à libérer de la mémoire.

Si vous vous inquiétez des performances lors du redimensionnement d'une chaîne, il existe une fonction reserve qui peut vous être utile.

2
unwesen

si vous utilisez le tableau de caractères dans un texte similaire, etc. utilisez std :: string plus flexible et plus facile à utiliser. Si vous l'utilisez pour autre chose comme le stockage de données? utiliser des tableaux (préférez les vecteurs)

1
RvdK

Même lorsque les performances sont cruciales, il vaut mieux utiliser vector<char> - il permet l'allocation de mémoire à l'avance (méthode reserve ()) et vous aidera à éviter les fuites de mémoire. L'utilisation de vector :: operator [] conduit à une surcharge, mais vous pouvez toujours extraire l'adresse du tampon et l'indexer exactement comme s'il s'agissait d'un char *.

1
sharptooth