开发者

Alternative to boost::lexical_cast

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):

  1. some benchmarks
    • https://cppsoup.wordpress.com/2010/01/08/boost-spirit-v2-x-versus-cs-atoi/
    • karma benchmark in documentation
  2. See also my other answer atoi on a character array with lots of integers
  3. 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.

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜