8
votes

Pourquoi STD :: string_view :: Les données ne comprennent pas un terminateur null?

Ce code a un comportement indéfini:

std::string str{ msg };
std::cout << str.data() << '\n';


10 commentaires

ERR, mais un string-littéral est résilié par NULL.


@Whiztim Que voulez-vous dire?


Je ne vois pas pourquoi vous avez besoin de data à NULL terminé. Si vous lui donnez un NULL terminé const char * la vue l'avoir toujours. Si vous n'en avez pas, la vue n'en ajoutera pas une. C'est le comportement attendu IMHO.


@Nathanoliver Si j'appelle foo ("foo") , la vue de la chaîne ne sera pas terminée null, même si le littéral est. Pour des raisons pratiques, où vous avez besoin d'une chaîne terminée nulle, ce serait bien d'avoir une telle fonction s'il n'y a pas d'alternative.


@ Rakete1111 vraiment?!? Si cela est vrai, alors oui, il est cassé.


@Nathanoliver Voir constructeur (4) "Construit une vue de la chaîne de caractères terminée null pointée par s, sans inclure le caractère null de terminaison." EN.CPPREFERFERATION.COM/W/CPP/String/basic_string_view/...


@ Rakete1111 oh wow. Ce n'est pas intuitif du tout. J'espère que les directives de base Array_View font mieux.


Cela signifie simplement que la taille de l'octet String_View n'inclut pas l'octet NULL. Mais bien sûr, la chaîne réelle pointée est toujours désignée.


@ Rakete1111, tandis que nous ne devrions pas compter sur std :: string_view :: data () , car nous pouvons construire une vue non nulle terminée à l'aide du std :: string_view (const char * , std ::ze_t) constructeur et le constructeur par défaut . Je ne vois pas de moyen légal de construire une vue non terminée non nulle à l'aide du std_ding_view (const char *) constructeur (selon votre exemple) sans invoquer déjà UB. Parce que ce constructeur appelle supposément des appels std :: Char_Traits :: Longueur pour déterminer la longueur de la chaîne qui nécessite un terminateur null.


Aussi loin que j'ai compris std :: string_view est supposé prendre uniquement des données (en tant que paramètre) pour ne pas le transmettre. C'est plus ou moins juste un pointeur plus la longueur et peut être utilisé à la place de (const char * données, taille_t len) . De plus, il ne copie aucune donnée qui le rend préférable sur std :: string dans certains cas. Je pense que tout _view s fonctionne comme ça.


3 Réponses :


19
votes

Alors, pourquoi STD :: string_view :: Les données ne renvoient pas une résiliation null String comme STD :: String :: Données

Tout simplement parce que ça ne peut pas. Un string_view peut être une vue plus étroite dans une chaîne plus grande (une sous-chaîne d'une chaîne). Cela signifie que la chaîne visualisée ne sera pas nécessaire la résiliation null à la fin d'une vue particulière. Vous ne pouvez pas écrire le terminateur NULL dans la chaîne sous-jacente pour des raisons évidentes et vous ne pouvez pas créer de copie de la chaîne et de retourner char * sans fuite de mémoire.

si Vous voulez une chaîne de terminaison null, vous devrez créer un std :: string en dehors de celui-ci.

Permettez-moi d'utiliser une bonne utilisation de std :: string_view : xxx

ici Le vecteur résultant contient des jetons comme une vue sur la chaîne plus grande.


0 commentaires

12
votes

Le but de string_view doit être une plage représentant une séquence contiguë de caractères. Limiter une telle plage à celle qui se termine dans un terminateur nul limite l'utilité de la classe.

qui étant dit, il serait toujours utile d'avoir une version alternative de string_view qui est destiné uniquement. Pour être créé à partir de chaînes qui sont vraiment terminées nules.

mon zstring_view Classe est hérité en privé à partir de string_view , et fournit un support pour supprimer des éléments de les opérations avant et autres qui ne peuvent pas rendre la chaîne non nulée non nulée. Il fournit le reste des opérations, mais ils renvoient un string_view , pas un zstring_view .

Vous seriez surpris de quelle quantité d'opérations que vous devez Perdre de string_view pour faire ce travail: xxx


2 commentaires

Donc, zstring_view ne peut être qu'une vue dans la queue d'une chaîne. Intéressant.


Quelqu'un a-t-il proposé une telle classe d'inclusion dans la norme? Il serait vraiment utile d'interoper des bibliothèques C, d'éviter de construire des types de chaîne complètes C ++ dans leurs interfaces si un littéral à chaîne peut être enveloppé / visualisé à la place.



1
votes

Lorsque vous traitez avec des littéraux à chaîne avec des terminateurs nuls connus, j'utilise habituellement quelque chose comme ça pour vous assurer que la null est incluse dans les caractères comptés.

auto view = string_viewz("Surrogate String");


4 commentaires

Faites-le consexpr et c'est parfait :) De plus, vous n'avez pas vraiment besoin de la fonction, string_view ("test") fonctionne.


string_view ("test"). Taille () == 4; string_viewz ("test"). Taille () == 5;


Cela ne fera que vous aider avec une vue String_View d'une chaîne complète terminée NULL; Il ne fonctionnera pas correctement si la vue est une sous-chaîne d'une plus grande chaîne


Vous avez raison LXOP. J'essaie de dire que dans la réponse, mais je peux voir comment ce que j'ai écrit pourrait être plus succinct.