Is there a more stringent version of std::stoi which will throw when an input really is not a valid integer? Or do I have to roll my own?
You will have to roll your own, because your demands clash with the one, consistent, unsurprising way in which all "string to integer" functionality in both C and C++ is defined.
First off, you'd have to come up with your definition of "a valid integer". Do you accept leading 0 (octal), leading 0x (hexadecimal), and / or leading 0b (binary)? Do you accept leading whitespace?
If you're OK with both, your workaround is good enough. Otherwise, you'd have to check the first character of your string to be isdigit
as well as being non-null.
I just discovered (much to my surprise) that the following inputs do not cause std::stoi to throw an exception:
Reading a good reference on any function you are not very familiar with before using it is a rather basic requirement.
That reference states very clearly that, after skipping any leading whitespace, it will take "as many characters as possible" to form "a valid [...] integer number representation", and that the second argument "will receive the address of the first unconverted character".
Violating the principle of least surprise - since none of these are valid format integer values.
Note, perhaps even more surprisingly 3.8 is converted to the value 3.
Is there a more stringent version of std::stoi which will throw when an input really is not a valid integer? Or do I have to roll my own?
There is one significant problem here: You have made assumptions, haven't bothered to check them with a reference, and are now digging in your heels that you know better. Not only is the behavior you observed internally consistent with all of C++'s istream operator>>
, std::sto*
family, and C's *scanf
, strto*
, and ato*
family. It is also how Java's Scanner.nextInt()
, C#'s int.TryParse
, Perl's int
, and similar functions from a dozen other languages work.
(By the way, this is also true for the various floating-point parsing functions as well.)
Why is std::stoi
implemented this way?
Because this is the most efficient implementation for the general use-case.
The only practical use this function has is to desperately try and obtain some integer value from random garbage input - which doesn't seem like a very useful function.
Consider:
4;3.14;16
That is clearly not "random garbage input", but semicolon-separated data -- something encountered quite often, you will agree.
If "reading an int" would throw an exception at a non-digit input, like you suggest, we would be looking at a minimum of two exceptions being thrown for parsing this very non-exceptional line of input. Alternatively, we would have to pass over that input twice, first for finding the semicolons / line ends (and either having to write into the input string or setting up several temporary variables), then a second time for parsing. That would be very inefficient.