Pourquoi std :: ssize () est-il introduit dans C ++ 20?

99

C ++ 20 a introduit lestd::ssize() fonction gratuite comme ci-dessous:

template <class C>
    constexpr auto ssize(const C& c)
        -> std::common_type_t<std::ptrdiff_t,
                              std::make_signed_t<decltype(c.size())>>;

Une implémentation possible semble utiliser static_cast, pour convertir la valeur de retour de la size()fonction membre de cl ass C en son équivalent signé.

Depuis le size() fonction membre de C renvoie toujours des valeurs non négatives, pourquoi quelqu'un voudrait-il les stocker dans des variables signées? Au cas où on le voudrait vraiment, c'est simple static_cast.

Pourquoi est std::ssize()introduit dans C ++ 20?

John Z. Li
la source
4
@ Jarod42 N'est-ce pas une implémentation définie au lieu d'indéfinie? (le débordement signé n'est pas défini. mais la conversion signée est définie par l'implémentation)
phön
8
Si seulement ils ajoutent également un ssizeofopérateur.
geza
3
Cela pourrait être un peu lié: stackoverflow.com/questions/30395205/…
Marco13
10
@ JohnZ.Li Au risque de paraître trop peu structurel: je pense que tout le système de types de C ++ concernant les types entiers est cassé. Bien sûr, on peut affirmer que certaines bizarreries (comme ne pas savoir combien de bits chara) sont héritées de C et au moins quelque peu atténuées par (u)intX_t, mais c'est toujours une source infinie de bogues tout aussi subtils et critiques. Des choses comme ssizene sont que des correctifs, et cela prendra un certain temps (peut-être "pour toujours") jusqu'à ce que cela pénètre dans les "guides des meilleures pratiques" que les gens (peuvent) suivre rigoureusement.
Marco13
6
@ Marco13: D'un autre côté, le système de type C / C ++ (contrairement au système de types fixes de Java par exemple), en plus de permettre au code C / C ++ de travailler sur des architectures où la plupart des autres langages croassent, permet aux instructeurs compétents d'obtenir des leçons dans la tête d'un élève. Comme, tout le monde n'est pas en 64 bits. Et non, tout le monde n'utilise pas de caractères 8 bits. Il est extrêmement facile de gérer ces choses et cela fait de vous un meilleur développeur, si seulement les instructeurs enseignaient cela dès le début . (Et, juste pour vous assurer, vous ne savez que les (u)intX_ttypes sont en option , pensez - vous?)
DevSolar

Réponses:

69

La justification est décrite dans cet article . Une citation:

Lorsque span a été adopté dans C ++ 17, il a utilisé un entier signé à la fois comme index et comme taille. C'était en partie pour permettre l'utilisation de "-1" comme valeur sentinelle pour indiquer un type dont la taille n'était pas connue au moment de la compilation. Mais avoir un conteneur STL dont la fonction size () retournait une valeur signée était problématique, donc P1089 a été introduit pour "résoudre" le problème. Il a reçu le soutien de la majorité, mais pas la marge de 2 contre 1 nécessaire au consensus.

Ce papier, P1227, était une proposition d'ajouter des fonctions non-membres std :: ssize et membre ssize (). L'inclusion de ceux-ci rendrait certains codes beaucoup plus simples et permettrait d'éviter les non-signés indésirables dans les calculs de taille. L'idée était que la résistance à P1089 diminuerait si ssize () était disponible pour tous les conteneurs, à la fois via std :: ssize () et en tant que fonctions membres.

Nadav Har'El
la source
30
L' for(int i = 0; i < container.ssize() - 1; ++i)exemple est également assez convaincant
Caleth
7
@John il me semble en effet qu'ils pourraient faire la même chose que string :: npos et utiliser juste size_t (-1) comme valeur spéciale.
rubenvb
15
@ JohnZ.Li Le fait que les types de taille STL ne soient pas signés a longtemps été considéré comme une erreur. Maintenant, malheureusement, il est trop tard pour le réformer. Offrir une fonction gratuite est le mieux que nous puissions faire pour le moment.
LF
16
@LF: C'était Herb Sutter lors d'une conférence (peut-être que Bjarne l'a dit aussi). Mais, il a un peu tort. Maintenant, avec les ordinateurs 32 bits / 64 bits, la taille signée serait meilleure (il a donc raison). Mais dans l'ancien temps (tailles 16 bits), la taille signée aurait été mauvaise (par exemple, nous aurions pu allouer des tableaux de 32 ko uniquement).
geza
11
@LF: J'ai trouvé Herb mentionnant ceci: youtube.com/watch?v=Puio5dly9N8&t=2667 . Quand il dit que "cela ne revient pas beaucoup dans la pratique", c'est vrai de nos jours. Mais ce n'était pas du tout vrai il y a plus de 20 ans (systèmes 16 bits). Ce n'était donc pas une erreur d'utiliser non signé, lorsque la STL a été conçue.
geza
50

Volé gratuitement à Eric Niebler:

'Unsigned types signal that a negative index/size is not sane'était la sagesse dominante lors de la conception initiale de la STL. Mais logiquement, le décompte des choses n'a pas besoin d'être positif. Je peux vouloir garder un compte dans un entier signé pour indiquer le nombre d'éléments ajoutés ou supprimés d'une collection. Ensuite, je voudrais combiner cela avec la taille de la collection. Si la taille de la collection n'est pas signée, je suis maintenant obligé de mélanger l'arithmétique signée et non signée, qui est une ferme de bogues. Les compilateurs avertissent à ce sujet, mais comme la conception de la STL force à peu près les programmeurs dans cette situation, l'avertissement est si courant que la plupart des gens l'éteignent. C'est dommage car cela cache de vrais bugs.

L'utilisation d'entiers non signés dans les interfaces n'est pas l'avantage que beaucoup de gens pensent que c'est. Si par accident un utilisateur transmet un nombre légèrement négatif à l'API, il devient soudainement un nombre positif énorme. Si l'API avait pris le nombre comme signé, elle pouvait alors détecter la situation en affirmant que le nombre était supérieur ou égal à zéro.

Si nous limitons notre utilisation des entiers non signés au twiddling de bits (par exemple, les masques) et utilisons des entiers signés partout ailleurs, les bogues sont moins susceptibles de se produire et plus faciles à détecter lorsqu'ils surviennent.

sp2danny
la source
6
Swift adopte cette approche, même s'il ne craint pas que les nombres signés négatifs soient réinterprétés comme des nombres massifs non signés (car il n'y a pas de cast implicites, ce qui vous amène vraiment dans cette maison amusante folle pour commencer). Ils adoptent simplement l'approche (la taille du mot machine) Intdevrait être les types de monnaie courants des nombres entiers, même lorsque seuls les nombres positifs ont un sens (comme l'indexation d'un tableau). Tout écart par rapport à celui-ci doit être fondé. C'est bien de ne pas avoir à s'inquiéter des lancers partout.
Alexander - Réintègre Monica