Safely convert std::string_view to int (like stoi or atoi)

Phil-ZXX picture Phil-ZXX · Jun 17, 2019 · Viewed 7.1k times · Source

Is there a safe standard way to convert std::string_view to int?


Since C++11 std::string lets us use stoi to convert to int:

  std::string str = "12345";
  int i1 = stoi(str);              // Works, have i1 = 12345
  int i2 = stoi(str.substr(1,2));  // Works, have i2 = 23

  try {
    int i3 = stoi(std::string("abc"));
  } 
  catch(const std::exception& e) {
    std::cout << e.what() << std::endl;  // Correctly throws 'invalid stoi argument'
  }

But stoi does not support std::string_view. So alternatively, we could use atoi, but one has to be very careful, e.g.:

  std::string_view sv = "12345";
  int i1 = atoi(sv.data());              // Works, have i1 = 12345
  int i2 = atoi(sv.substr(1,2).data());  // Works, but wrong, have i2 = 2345, not 23

So atoi does not work either, since it is based off the null-terminator '\0' (and e.g. sv.substr cannot simply insert/add one).

Now, since C++17 there is also from_chars, but it does not seem to throw when providing poor inputs:

  try {
    int i3;
    std::string_view sv = "abc";
    std::from_chars(sv.data(), sv.data() + sv.size(), i3);
  }
  catch (const std::exception& e) {
    std::cout << e.what() << std::endl;  // Does not get called
  }

Answer

Ron picture Ron · Jun 17, 2019

The std::from_chars function does not throw, it only returns a value of type from_chars_result which is a struct with two fields:

struct from_chars_result {
    const char* ptr;
    std::errc ec;
};

You should inspect the values of ptr and ec when the function returns:

#include <iostream>
#include <string>
#include <charconv>

int main()
{
    int i3;
    std::string_view sv = "abc";
    auto result = std::from_chars(sv.data(), sv.data() + sv.size(), i3);
    if (result.ec == std::errc::invalid_argument) {
        std::cout << "Could not convert.";
    }
}