std::string : du texte qui se gère tout seul
À la page précédente, vous avez vu comment les pointeurs intelligents permettent à un objet de posséder une ressource et de la nettoyer automatiquement. std::string, c'est cette même idée appliquée au texte : il possède un tampon de caractères, l'agrandit quand vous ajoutez du contenu et le libère quand la chaîne sort de portée. Vous n'appelez jamais new, ne comptez jamais d'octets et ne vous souciez jamais d'un terminateur nul manquant.
Pour l'utiliser, incluez <string>. La classe vit dans l'espace de noms std.
Cet opérateur + fait un vrai travail - il alloue un nouveau tampon assez grand pour les deux morceaux et les y copie. Avec un char* brut, vous devriez recourir à strcpy et strcat en espérant que votre tampon soit assez grand. std::string fait disparaître toute cette catégorie d'erreurs.
Construire et assembler des chaînes
Vous pouvez concaténer avec +, mais le cheval de bataille pour faire grandir une chaîne sur place est +=. Il ajoute au tampon existant au lieu de produire une chaîne flambant neuve à chaque fois, ce qui compte à l'intérieur des boucles.
Une surprise fréquente : + exige qu'au moins un des opérandes soit déjà un std::string. Deux littéraux de chaîne ne sont que des const char*, donc "a" + "b" ne compile pas - il n'existe pas d'operator+ pour deux pointeurs bruts. Transformez d'abord l'un d'eux en chaîne :
string s = "a" + "b"; // error: can't add two const char*
string s = string("a") + "b"; // fine - left side is a std::string
string s = "a"s + "b"; // fine in C++14+, the "s" literal suffix
Notez que cette dernière forme utilise le suffixe s de <string> (using namespace std::string_literals;), qui transforme directement un littéral en std::string.
Plonger dans une chaîne
Un std::string se comporte comme un conteneur de char, vous pouvez donc l'indexer, le parcourir et lui demander des morceaux.
substr(pos, len) renvoie une chaîne flambant neuve copiée de l'originale ; elle ne modifie pas la source. Attention aux bornes : word[10] sur une chaîne de 5 caractères est un comportement indéfini - il ne lance rien, il lit simplement des données aléatoires. Si vous voulez un accès vérifié qui lance std::out_of_range, utilisez word.at(10) au lieu de word[10].
Autre piège classique : .size() renvoie un type non signé (size_t). Écrire une boucle à rebours comme for (size_t i = word.size() - 1; i >= 0; --i) ne se termine jamais, car un i non signé ne peut jamais passer sous zéro - il déborde et devient un nombre énorme. Utilisez un indice signé ou réorganisez la condition lorsque vous devez parcourir une chaîne à l'envers.
Rechercher et remplacer
find localise une sous-chaîne ou un caractère et renvoie l'indice de départ. Quand la cible est absente, il renvoie la constante spéciale std::string::npos - comparez toujours à elle plutôt que de supposer que find renvoie -1.
Pour modifier du texte sur place, replace(pos, len, text) échange une portion contre un nouveau contenu (qui peut être de longueur différente), et insert/erase ajoutent ou retirent des morceaux :
Chaînes et nombres
Le texte et les nombres ne se convertissent pas tout seuls - "42" fait trois caractères, pas l'entier 42. La bibliothèque standard vous offre des fonctions de conversion dans les deux sens. Utilisez stoi, stod et compagnie pour analyser du texte en nombres, et to_string pour aller dans l'autre direction.
Deux pièges ici. D'abord, stoi("abc") lance std::invalid_argument, alors protégez l'entrée non fiable avec un bloc try/catch. Ensuite, to_string(3.99) donne le 3.990000 complet - si vous avez besoin de contrôler la précision et la mise en forme, c'est le travail des flux de chaînes (string streams), précisément là où nous allons ensuite.
try {
int n = std::stoi(userInput);
} catch (const std::invalid_argument&) {
std::cout << "That wasn't a number.\n";
}
Ensuite : entrée et sortie
Vous affichez des chaînes avec cout depuis le début, mais les relire depuis l'utilisateur réserve ses propres surprises - cin >> name s'arrête au premier espace, donc une ligne entière comme "Ada Lovelace" nécessite plutôt std::getline. La page suivante traite correctement l'entrée et la sortie en C++ : opérateurs de flux, lecture de lignes entières et mélange de >> avec getline sans trébucher sur les sauts de ligne résiduels.
Questions fréquentes
Quelle est la différence entre std::string et char* en C++ ?
std::string est une classe qui possède et gère sa propre mémoire, s'agrandit au besoin et se nettoie automatiquement. Un char* n'est qu'un pointeur brut vers des caractères avec un '\0' terminateur - c'est vous qui gérez le tampon, la longueur et la durée de vie. Préférez std::string pour presque tout ; il élimine des catégories entières de bugs de débordement de tampon et de pointeurs pendants.
Comment obtenir la longueur d'une chaîne en C++ ?
Appelez .size() ou son alias .length() sur un std::string : name.size() renvoie le nombre de caractères sous forme de size_t. Les deux renvoient la même valeur ; size() est le style le plus courant car il s'accorde avec tous les autres conteneurs de la STL.
Comment convertir une chaîne en nombre en C++ ?
Utilisez std::stoi pour int, std::stod pour double et leurs équivalents (stol, stof). Exemple : int n = std::stoi("42");. Ces fonctions lancent std::invalid_argument si le texte n'est pas un nombre, alors enveloppez-les dans un try/catch quand l'entrée n'est pas de confiance.