L’arrivée de C++17 – std::string_view

Bonjour à tous et bienvenue pour ce nouvel article sur C++17 traitant de std::string_view.

C++17 a introduit std::string_view, qui permet de manipuler des vues constantes sur des chaînes de caractères :

string_view ne stocke pas la chaîne de caractères en elle-même. Une implémentation consiste à stocker le pointeur vers le premier élément ainsi que la taille.

Ainsi, string_view peut être passée par valeur comme c’est le cas dans la fonction print ci-dessus. Aucune allocation n’a lieu puisque la chaîne de caractères n’est pas copiée.

std::string_view propose un certain nombre de constructeurs et de conversions permettant de créer une vue à partir de tableau de char et de std::string :

Notez que std::string_view n’a pas connaissance de la durée de vie des données. Elle ne possède pas la mémoire et peut donc contenir un pointeur invalide si la chaîne est détruite, ce qui arrive si on crée la vue à partir d’un temporaire par exemple :

Tout comme std::string est un alias sur std::basic_string<char>, std::string_view est un alias sur std::basic_string_view<char>. Il existe donc un type vue pour chaque type de chaîne de caractères :

  • std::string_view : std::basic_string_view<char>.
  • std::wstring_view : std::basic_string_view<wchar_t>.
  • std::u8string_view : std::basic_string_view<char8_t>. (depuis C++20)
  • std::u16string_view : std::basic_string_view<char16_t>.
  • std::u32string_view : std::basic_string_view<char32_t>.

Pourquoi et quand utiliser std::string_view ?

std::string_view ne fait donc pas de copie de la chaîne sous-jascente lorsque l’on la passe en paramètre, mais c’est également le cas de const std::string&. Alors pourquoi utiliser std::string_view ?

Tout d’abord, char* est convertible en std::string_view sans copie, contrairement à std::string qui copie la mémoire lors de la construction :

Il est donc préférable d’avoir un paramètre de type string_view, qui n’effectuera pas de copie à partir d’une string ou d’un tableau style C.

De plus, étant une vue, certaines opérations sont nettement moins coûteuses, notamment lorsqu’il s’agit de travailler avec des sous-chaînes.

En effet, std::string::substr doit effectuer la copie de la sous-chaîne de manière à renvoyer l’objet std::string contenant cette sous-chaîne. std::string_view::substr va créer un nouveau objet string_view avec une range différente. D’un point de vue mémoire, une seule chaîne de caractères existe avec deux vues. La complexité est linéaire pour std::string et constante pour std::string_view (un petit benchmark).

Plus encore, une référence implique une possibilité d’aliasing, ce qui implique que les outils d’analyse statique (dont les passes d’optimisation du compilateur) auront plus de facilité à raisonner avec des std::string_view.

Est-ce qu’il faut toujours remplacer nos vieux const std::string& par std::string_view ? Et bien, oui et non. Les raisons d’utiliser const std::string& ne sont plus très nombreuses désormais.

Le principal argument de const std::string& est qu’il permet de traiter des chaînes null-terminated (dont la fin est délimitée par un caractère nul '\0'), ce que std::string_view ne sait pas faire (puisque qu’une slice connait sa taille). C’est le plus souvent le cas quand on travaille avec une API écrite en C.

En dehors de ce cas précis, on préférera utiliser string_view lorsqu’on ne fait que lire la chaîne.

Opérations

Puisqu’il s’agit d’une vue constante, les fonctions membres de std::string qui modifient la chaîne telles que erase, push_back, swap,  append, ou encore replace n’existent pas pour std::string_view .

En revanche, l’interface de string_view  fourni les fonctions membres constantes classiques : copy, substr, compare, capacity, les itérateurs et j’en passe.

string_view propose aussi les fonctions membres remove_prefix et remove_suffix qui retournent une vue rétrécie.

Ajoutez à cela les deux fonctions starts_with et ends_with de C++20, qui ont également été ajoutées pour std::basic_string. et nous avons déjà un bon aperçu du fonctionnement de string_view :).

Voilà donc pour aujourd’hui, je vous remercie de votre lecture et vous dis à bientôt !

Références et ressources

%d bloggers like this: