3 Réponses :


1
votes

Ce n'est pas si étrange.

Si vous lui donnez une valeur hors plage, c'est votre erreur. Il ne serait pas juste de nous forcer tous à endurer des contrôles sans fin juste pour attraper cet événement rare.

De même, il n'est pas juste de s'attendre à ce que les opérations bien définies de ce type fassent quoi que ce soit en particulier sur des valeurs qui sont expressément considérées comme hors limites, ni le type de résultat déterministe que vous attendez d'une telle opération. . Quel jour vient après "ooglebooglebargleday"?

Vous trouverez beaucoup cette philosophie dans C ++. Vous ne payez pas pour ce que vous n'utilisez pas, et vous pouvez vous tirer une balle dans le pied tant que cela ne vous dérange pas de devoir vous porter le reste du chemin du retour.


6 commentaires

Pourquoi le jour de la semaine n'a-t-il pas d'invariant qui stocke une valeur dans [0, 6] ? Ce serait une seule vérification (éventuellement uniquement pour le débogage) dans un constructeur, pas partout. Au lieu de cela, il permet explicitement de stocker des valeurs invalides qui semblent étranges.


@vitaut Je ne serais pas surpris de voir une telle vérification dans le débogage, mais c'est un problème d'implémentation. Ici, le contrat est clairement énoncé (votre catégorisation de ceci comme "permet explicitement de stocker des valeurs invalides" ne semble pas être une déclaration juste) et si le programmeur le rompt, c'est la faute du programmeur. Il existe des centaines d'autres cas de ce type dans C ++, comme vous le savez sûrement. Quel comportement alternatif attendez-vous? Une exception, ou?


La norme semble interdire une telle vérification par une formulation explicite selon laquelle des valeurs invalides sont autorisées. C'est ce qui me frappe le plus. Peut-être que je ne comprends pas simplement «peut».


@vitaut je ne pense pas. Le paragraphe 1 dit "Il peut être construit avec n'importe quelle valeur non signée, qui sera ensuite tronquée pour s'adapter à la mémoire interne non spécifiée du jour de la semaine." Vous pouvez donc lui donner la valeur que vous voulez, et si vous le faites < i> peut voir une valeur hors limites, ou vous ne pouvez pas, et une implémentation peut contraindre cela à son contenu. Encore une fois, assez habituel pour C ++. Considérez ce qui se passe lorsque vous dépassez un entier signé.


@vitaut Dites-vous ce que mais je suis d'accord pour dire que dans l'ensemble, la sémantique de cette section n'est pas la meilleure de C ++. par exemple. [time.cal.wd.members] / 1 nomme spécifiquement la plage [0,255] car un caractère non signé est impliqué dans le synopsis. Il est un peu fuyant. Je vous préviens de vous rappeler que ce n’est pas la norme, qu’il s’agit d’une nouvelle fonctionnalité dans un brouillon de travail, et elle est sujette à changement et sujette à des suggestions ... et vous pourriez continuer la liste de diffusion et parler de son amélioration;)


(Intègrera probablement certaines de ces pensées dans la réponse dans un instant)



4
votes

Pourquoi le jour de la semaine a-t-il un comportement si particulier, en particulier pourquoi les valeurs en dehors de [0, 6] sont-elles autorisées mais pas préservées par des opérations arithmétiques?

Toute opération arithmétique le jour de la semaine risque de déborder. Donc vous devez faire une opération modulo là-bas. Il est important que sam + jours {1} == soleil , car c'est ce à quoi tout le monde s'attend. Et vous voulez vraiment que (sam + jours {1}). Ok () se tienne également, car c'est sûrement valide. Et il est tout aussi important que sam + jours {8} == soleil et sam + jours {701} == soleil , et ainsi de suite. C'est ainsi que fonctionne l'arithmétique des calendriers.

Il est donc assez nécessaire de faire un modulo 7 sur toutes les opérations arithmétiques. Il est tout simplement inutile de conserver 8 comme valeur du jour de la semaine - ce n'est pas vraiment un jour de semaine valide.

D'un autre côté, faire le modulo sur la construction n'a pas autant de valeur claire. C'est un travail supplémentaire que vous n'aurez peut-être pas besoin de faire, et cela pourrait même cacher des bogues. Que faire si vous voulez simplement valider jour de la semaine (user_input) .ok () ? Est-ce que tout le monde qui a besoin de savoir quoi vérifier en externe?

En bref, les valeurs supérieures à 6 sont autorisées lors de la construction, car cela a du sens de les autoriser, mais l'arithmétique ne les conserve pas car cela n'a pas de sens de les conserver.

Mais Howard est un contributeur fréquent à SO, donc il vous proposera probablement une meilleure réponse .


5 commentaires

Les opérations modulo ont un sens parfait pour moi, mais le libellé interdisant les vérifications de valeurs invalides semble étrange.


De plus, le fait que la valeur invalide devienne silencieusement valide après une opération est un peu une arme à feu.


@Caleth Non, sat + jours {8} doit absolument être égal à sun .


Ah, je me trompe jours pour jour (de même jour de semaine ). La norme actuelle exige uniquement que jour et jour de la semaine soient spécifiés s'ils sont fournis dans la plage [0, 255]


"cela n'a pas de sens de les préserver" Je ne suis pas du tout d'accord. Il est logique de les préserver pour les mêmes raisons qu'il est logique de préserver les NaN. Ils représentent des valeurs invalides ( ok () == false ). Nous voudrions peut-être ne pas les conserver pour des raisons de performances, mais c'est un compromis entre l'exactitude et les performances.



10
votes

Le constructeur jour de la semaine (wd non signé) promet de contenir toute valeur dans l'intervalle [0, 255]. La raison en est:

  1. C'est très rapide.
  2. Il permet à un client d'attribuer une valeur "inutilisée" à quelque chose d'utile dans la logique du client.

Pour un exemple de (2):

constexpr weekday not_a_weekday{255};
...
weekday wd = not_a_weekday;
in >> wd;
if (wd == not_a_weekday)
    throw "oops";

jour de la semaine l'arithmétique force la plage à revenir en [0, 6] parce que si vous écrivez l'algorithme pour faire de l'arithmétique modulo 7, sans aucune vérification de plage, c'est ce qui se passe naturellement. C'est à dire. c'est la chose la plus rapide à faire.


Donc en résumé: les performances sont la raison d'être de la spécification jour de la semaine actuelle, combinée à une sizeof ce qui est aussi petit que possible (ce qui peut également contribuer à la performance).

Quelle que soit la performance possible, quels que soient les comportements restants (se produisent naturellement) peuvent être bénéfiques pour standardiser et permettre aux clients de profiter de ces comportements plutôt que de dire qu'ils sont un comportement indéfini TM.

En effet, la spécification évite UB autant que possible, optant plutôt pour un comportement non spécifié. Par exemple, le jour de la semaine {300} peut ne pas stocker la valeur souhaitée, mais ne peut pas reformater votre disque et l'optimiseur n'est pas autorisé à prétendre que le code n'existe pas .


3 commentaires

Les considérations de performances ont du sens, même si j'ai des sentiments mitigés sur le fait que les jours de la semaine invalides deviennent valides après certaines opérations et l'incapacité des implémentations à introduire des vérifications de débogage.


Voici une façon amusante de forcer un jour de la semaine dans une plage valide: wd + = jours {0};


La spécification permet aux clients d'introduire des contrôles de débogage à un niveau supérieur, là où cela a du sens dans la logique du client. Et parfois, une valeur ! Ok () n'est pas une erreur dans la logique du client. Par exemple: github.com/HowardHinnant/date/wiki/…