J’ai eu une belle conversation avec quelqu’un au sujet des inconvénients de std::stoi
. Pour le dire franchement, il utilise std::strtol
interne et lance si cela signale une erreur. Selon eux, cependant, std::strtol
ne devrait pas signaler une erreur pour une entrée de "abcxyz"
, stoi
de lancer std::invalid_argument
.
Tout d’abord, voici deux programmes testés sur GCC concernant les comportements de ces cas:
strtol
stoi
Les deux montrent le succès sur "123"
et l’échec sur "abc"
.
J’ai regardé dans la norme pour tirer plus d’informations:
§ 21.5
Throws: invalid_argument if strtol, strtoul, strtoll, or strtoull reports that no conversion could be performed. Throws out_of_range if the converted value is outside the range of representable values for the return type.
Cela résume le comportement de compter sur strtol
. Maintenant, qu’en est-il de strtol
? Je l’ai trouvé dans le projet C11:
§7.2.2.1.4
If the subject sequence is empty or does not have the expected form, no conversion is performed; the value of nptr is stored in the object pointed to by endptr, provided that endptr is not a null pointer.
Compte tenu de la situation de passage à "abc"
, le standard C stipule que nptr
, qui pointe vers le début de la chaîne, serait stocké dans endptr
, le pointeur transmis. Cela semble cohérent avec le test. De plus, 0 devrait être retourné, comme indiqué par ceci:
§7.2.2.1.4
If no conversion could be performed, zero is returned.
La référence précédente indiquait qu’aucune conversion ne serait effectuée, elle doit donc retourner 0. Ces conditions sont désormais conformes à la norme C ++ 11 pour stoi
std::invalid_argument
.
Le résultat de ceci est important pour moi parce que je ne veux pas contourner stoi
comme une meilleure alternative à d’autres méthodes de chaîne pour convertir un int, ou l’utiliser moi-même comme si vous le souhaitiez, si ça ne marche pas. t attraper le texte en tant que conversion non valide.
Donc après tout ça, je me suis trompé quelque part? Il me semble avoir une bonne preuve de cette exception. Est-ce que ma preuve est valide ou est-ce que std::stoi
n’est pas garanti pour lancer cette exception quand on lui donne "abc"
?
std::stoi
jette une erreur sur l’entrée "abcxyz"
? Oui.
Je pense que votre confusion peut provenir du fait que strtol
ne signale jamais une erreur, sauf en cas de dépassement de strtol
. Il peut signaler qu’aucune conversion n’a été effectuée, mais il ne s’agit jamais d’une condition d’erreur dans la norme C.
strtol
est défini de la même manière par les trois standards C, et je vous épargnerai les détails ennuyeux, mais il définit fondamentalement une “séquence de sujet” qui est une sous-chaîne de la chaîne d’entrée correspondant au nombre réel. Les quatre conditions suivantes sont équivalentes:
*endptr != nptr
(cela n’a de sens que si endptr
est non nul) Quand il y a un débordement, la conversion est toujours dite.
Or, il est clair que "abcxyz"
ne contient pas de nombre, la séquence de sujet de la chaîne "abcxyz"
doit être vide, de sorte qu’aucune conversion ne puisse être effectuée. Le programme C90 / C99 / C11 suivant le confirmera expérimentalement:
#include #include int main() { char *nptr = "abcxyz", *endptr[1]; strtol(nptr, endptr, 0); if (*endptr == nptr) printf("No conversion could be performed.\n"); return 0; }
Cela implique que toute implémentation conforme de std::stoi
doit invalid_argument
un argument invalid_argument
lorsqu’elle reçoit l’entrée "abcxyz"
sans argument de base facultatif.
std::stoi
a une vérification d’erreur satisfaisante? Non. La personne à qui vous avez parlé est correcte quand elle dit que std::stoi
est plus indulgente que de faire la vérification complète errno == 0 && end != start && *end=='\0'
après std::strtol
car std::stoi
silencieusement tous les caractères à partir du premier caractère non numérique de la chaîne.
En fait, le seul langage dont la conversion native se comporte un peu comme std::stoi
est le Javascript, et même alors, vous devez forcer la base 10 avec parseInt(n, 10)
pour éviter le cas spécial des nombres hexadécimaux:
input | std::atoi std::stoi Javascript full check ===========+============================================================= hello | 0 error error(NaN) error 0xygen | 0 0 error(NaN) error 0x42 | 0 0 66 error 42x0 | 42 42 42 error 42 | 42 42 42 42 -----------+------------------------------------------------------------- languages | Perl, Ruby, Javascript Javascript C#, Java, | PHP, C... (base 10) Python...
Remarque: il existe également des différences entre les langues dans la gestion des espaces et des signes redondants.
Je ne suis au courant d’aucune fonction intégrée qui fait cela, mais boost::lexical_cast
fera ce que vous voulez. Il est particulièrement ssortingct puisqu’il rejette même les espaces blancs, contrairement à la fonction int()
de Python. Notez que les caractères non valides et les dépassements entraînent la même exception, boost::bad_lexical_cast
.
#include int main() { std::ssortingng s = "42"; try { int n = boost::lexical_cast(s); std::cout << "n = " << n << std::endl; } catch (boost::bad_lexical_cast) { std::cout << "conversion failed" << std::endl; } }