Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Converting string to integer, double, float without having to catch exceptions

Tags:

c++

exception

I have a string which can be either a double, float or int. I would like to convert the string to the data type by making function calls. I am currently using functions such as stof and stoi which throw exceptions when the input is not a float or int. Is there another way to convert the strings without having to catch exceptions? Perhaps some function that passes a a pointer to a float as argument and just returns a boolean which represents the success of the function of call. I would like to avoid using any try catch statements in any of my code.

like image 311
RagHaven Avatar asked Jul 16 '14 15:07

RagHaven


3 Answers

Use a std::stringstream and capture the result of operator>>().

For example:

#include <string>
#include <iostream>
#include <sstream>

int main(int, char*[])
{
    std::stringstream sstr1("12345");
    std::stringstream sstr2("foo");

    int i1(0);
    int i2(0);

    //C++98
    bool success1 = sstr1 >> i1;
    //C++11 (previous is forbidden in c++11)
    success1 = sstr1.good();

    //C++98
    bool success2 = sstr2 >> i2;
    //C++11 (previous is forbidden in c++11)
    success2 = sstr2.good();

    std::cout << "i1=" << i1 << " success=" << success1 << std::endl;
    std::cout << "i2=" << i2 << " success=" << success2 << std::endl;

    return 0;
}

Prints:

i1=12345 success=1
i2=0 success=0

Note, this is basically what boost::lexical_cast does, except that boost::lexical_cast throws a boost::bad_lexical_cast exception on failure instead of using a return code.

See: http://www.boost.org/doc/libs/1_55_0/doc/html/boost_lexical_cast.html

For std::stringstream::good, see: http://www.cplusplus.com/reference/ios/ios/good/

like image 93
pzed Avatar answered Oct 23 '22 21:10

pzed


To avoid exceptions, go back to a time when exceptions didn't exist. These functions were carried over from C but they're still useful today: strtod and strtol. (There's also a strtof but doubles will auto-convert to float anyway). You check for errors by seeing if the decoding reached the end of the string, as indicated by a zero character value.

char * pEnd = NULL;
double d = strtod(str.c_str(), &pEnd);
if (*pEnd) // error was detected
like image 33
Mark Ransom Avatar answered Oct 23 '22 19:10

Mark Ransom


Mark Ransom, you hit the nail on the head. I understand RagHaven because in certain situations exceptions are a nuisance, and converting alphanumeric chains to doubles should be something light and fast, not subject to the exception handling mechanism. I found that a five-alphanumeric string sorting algorithm took more than 3 seconds because exceptions were thrown in the process and somewhere in the software something was complaining.

In my search for conversion functions without launching exceptions I found this (I work with C++ Builder):

double StrToFloatDef(string, double def);

That function tries to return a float, and, if it does not succeed, instead of launching an exception it returns the value that is passed in the 2nd argument (which could for example be put to std::numeric_limits<double>::max()). Checking if the return value matches 'def' you can control the result without exceptions.

Mark's proposal, std::strtod, is just as good but much faster, standard and safe. A function like the one RagHaven asks for could look like this:

bool AsDouble(const char* s, double& v) const noexcept
{
    char* pEnd = nullptr;
    v = std::strtod(s, &pEnd);
    return *pEnd == 0;
}
like image 32
Jose Avatar answered Oct 23 '22 20:10

Jose