Is std::stoi actually safe to use?

Does std::stoi throw an error on the input "abcxyz"?

Yes.

I think your confusion may come from the fact that strtol never reports an error except on overflow. It can report that no conversion was performed, but this is never referred to as an error condition in the C standard.

strtol is defined similarly by all three C standards, and I will spare you the boring details, but it basically defines a “subject sequence” that is a substring of the input string corresponding to the actual number. The following four conditions are equivalent:

  • the subject sequence has the expected form (in plain English: it is a number)
  • the subject sequence is non-empty
  • a conversion has occurred
  • *endptr != nptr (this only makes sense when endptr is non-null)

When there is an overflow, the conversion is still said to have occurred.

Now, it is quite clear that because "abcxyz" does not contain a number, the subject sequence of the string "abcxyz" must be empty, so that no conversion can be performed. The following C90/C99/C11 program will confirm it experimentally:

#include <stdio.h>
#include <stdlib.h>

int main() {
    char *nptr = "abcxyz", *endptr[1];
    strtol(nptr, endptr, 0);
    if (*endptr == nptr)
        printf("No conversion could be performed.\n");
    return 0;
}

This implies that any conformant implementation of std::stoi must throw invalid_argument when given the input "abcxyz" without an optional base argument.


Does this mean that std::stoi has satisfactory error checking?

No. The person you were talking to is correct when she says that std::stoi is more lenient than performing the full check errno == 0 && end != start && *end=='\0' after std::strtol, because std::stoi silently strips away all characters starting from the first non-numeric character in the string.

In fact off the top of my head the only language whose native conversion behaves somewhat like std::stoi is Javascript, and even then you have to force base 10 with parseInt(n, 10) to avoid the special case of hexadecimal numbers:

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...  

Note: there are also differences among languages in the handling of whitespace and redundant + signs.


Ok, so I want full error checking, what should I use?

I’m not aware of any built-in function that does this, but boost::lexical_cast<int> will do what you want. It is particularly strict since it even rejects surrounding whitespace, unlike Python’s int() function. Note that invalid characters and overflows result in the same exception, boost::bad_lexical_cast.

#include <boost/lexical_cast.hpp>

int main() {
    std::string s = "42";
    try {
        int n = boost::lexical_cast<int>(s);
        std::cout << "n = " << n << std::endl;
    } catch (boost::bad_lexical_cast) {
        std::cout << "conversion failed" << std::endl;
    }
}

1 thought on “Is std::stoi actually safe to use?”

  1. Really good post. I learn something mroe challenging on different blogs everyday. It is recommended stimulating to enjoy a book content from other writers and become familiar with a little something from their store. I want to apply certain of that content on my blog should you do not mind. Natually Ill give a link in to your internet site. Thanks for sharing.

    Reply

Leave a Comment