I'm trying to convert an std::string
to an int
with a default value if the conversion fails. C's atoi()
is way too forgiving and I've found that boost::lexical_cast
is quite slow in the case where the cast fails. I imagine it's because an exception is raised. I don't have C++11, so stoi()
is out.
The Delphi function StrToIntDef
is the ideal, and it's also available in C-Builder (where I'm working currently). But I want something more portable that works with std::string
.
I've created the following function, which uses atoi()
but first tests for error conditions. It also allows for leading and trailing spaces, which are harmless in my situation.
int stringtoIntDef(const std::string & sValue, const int & DefaultValue) {
// convert a std::string to integer with a default value returned
// in the case where the string doesn't represent a valid integer
// - accepts leading or trailing spaces as valid
bool hasDigits = false;
bool TrailingSpace = false;
for (std::string::size_type k = 0; k < sValue.size(); ++k) {
if ((sValue[k] == ' ') || (sValue[k] == '\t')) {
TrailingSpace = hasDigits;
} else if ((sValue[k] == '0') || (sValue[k] == '1') || (sValue[k] == '2') || (sValue[k] == '3') ||
(sValue[k] == '4') || (sValue[k] == '5') || (sValue[k] == '6') || (sValue[k] == '7') ||
(sValue[k] == '8') || (sValue[k] == '9')) {
if (TrailingSpace) {
return DefaultValue;
} else {
hasDigits = true;
}
} else if ((sValue[k] == '-') && !hasDigits) {
hasDigits = true; // this protects against "--"
} else {
return DefaultValue;
}
}
return atoi(sValue.c_str());
}
In my testing, I've compared it against StrToIntDef
and it is just as fast, but lexical_cast
is much slower in the case where the default is returned. For 1000 iterations, lexical_cast
took 5 seconds while the other 2 weren't measurable.
For my lexical_cast
function, I've used this:
try {
return boost::lexical_cast<int>(sValue);
}
catch (boost::bad_lexical_cast &) {
return DefaultValue;
}
Are there any gotchas I might have missed here?