I'm taking a part in a challenge, and just to cut to the point, in one of places in my program I need to convert string to an integer. I've tried boost::lexical_cast but unfortunatelly it is sooo sloowwww. I suppose because all of the checks it performs. What I need is something that would perform this conversion without any checks (I know that there will be valid numbers stored as strings). By the way using stringstream in the naive way:
stringstream interp开发者_JS百科reter;
interpreter << str;
interpreter >> number;
is even slower than boost::lexical_cast.
Is atoi the only alternative?You could do it using sscanf
but I suspect it's slower than atoi
as it handles locales.
You'll definitely be interested in reading this C++ Convert String to Int Speed benchmark that features a naive implementation that is faster than atoi
.
EDIT: Another post comparing different string to int implementations: C++ String to Int.
I can recommend Boost Spirit (parse with Qi):
- some benchmarks
- https://cppsoup.wordpress.com/2010/01/08/boost-spirit-v2-x-versus-cs-atoi/
- karma benchmark in documentation
- See also my other answer atoi on a character array with lots of integers
- some sample uses:
.
#include <boost/spirit/include/qi.hpp>
namespace qi = boost::spirit::qi;
const char *demo1 = "1234";
const char *demo2 = "1234,2345,-777,-888";
const char *demo3 = " 1234 , 2345 , -777, -888 ";
void do_demo1()
{
const char *begin = demo1;
const char *iter = begin;
const char *end = demo1+strlen(demo1);
int result;
if (qi::parse(iter, end, qi::int_, result))
std::cout << "result = " << result << std::endl;
else
std::cout << "parse failed at #" << (iter - begin) << ": " << std::string(iter, end) << std::endl;
//// to allow for spaces, use phrase_parse instead of parse
// if (qi::phrase_parse(begin, end, qi::int_, qi::space, result)
//// ... etc
}
void do_demo2()
{
const char *begin = demo2;
const char *iter = begin;
const char *end = demo2+strlen(demo2);
std::vector<int> results;
if (qi::parse(iter, end, qi::int_ % ',', results))
std::cout << "results = " << results.size() << std::endl;
else
std::cout << "parse failed at #" << (iter - begin) << ": " << std::string(iter, end) << std::endl;
}
void do_demo3()
{
const char *begin = demo3;
const char *iter = begin;
const char *end = demo3+strlen(demo3);
std::vector<int> results;
if (qi::phrase_parse(iter, end, qi::int_ % ',', qi::space, results))
std::cout << "results = " << results.size() << std::endl;
else std::cout << "parse failed at #" << (iter - begin) << ": " << std::string(iter, end) << std::endl;
}
int main()
{
do_demo1();
do_demo2();
do_demo3();
return 0;
}
Other
Be sure to look at binary (de)serialization IFF you can dictate the stream (text) format. See my recent answer here for a comparison of methods when aimed at serializing/deserializing:
- STL (unadorned ANSI C++98 standard library)
- Boost Spirit (above)
- Boost Serialization
That post includes benchmarks
For the Google Summer of Code I'm working on a new Boost library to tackle this; boost::coerce which can be found over here. The backend builds upon boost::spirit providing you all of its advantages (speed in particular) with a much simpler interface:
int i = boost::coerce::as<int>("23");
or
std::string s = boost::coerce::as<std::string>(23);
Note that it is still a work in progress, but should be sufficiently stable in practice. If any problems arise, please let me know.
strtol can be a better atoi (specifically w.r.t. error handling), and will be faster than lexical_cast.
The atoi/itoa functions are usually faster, as is sscanf().
All these are from the c runtime, but they should work well for you.
If you really don't need to do any checks, the quickest way could be to convert the string yourself. I mean to code something like this:
int integer_from(string s)
{
int n = 0;
for (string::const_iterator it = s.begin(); it != s.end(); it++)
{
n = 10*n + (*it) - '0';
}
return n;
}
how about using stoi(). I am sure that it must be fast enough to satisfy your needs.
精彩评论