Search code examples
c++stringstreamdata-conversion

efficiency of using stringstream to convert string to int?


Is the code below less (or more, or equally) efficient than:

make substring from cursor
make stringstream from substring
extract integer using stream operator

? (question edit) or is it less (or more, or equally) efficient than:

std::stoi

? and why?

Could this function be made more efficient?

(The class brings these into scope:)

std::string expression  // has some numbers and other stuff in it
int cursor              // points somewhere in the string

The code:

int Foo_Class::read_int()
{
    /** reads an integer out of the expression from the cursor */

    // make stack of digits
    std::stack<char> digits;

    while (isdigit(expression[cursor]))  // this is safe, returns false, for the end of the string (ISO/IEC 14882:2011 21.4.5)
    {
        digits.push(expression[cursor] - 48);  // convert from ascii
        ++cursor;
    }

    // add up the stack of digits
    int total = 0;
    int exponent = 0;  // 10 ^ exponent
    int this_digit;

    while (! digits.empty())
    {
        this_digit = digits.top();
        for (int i = exponent; i > 0; --i)
            this_digit *= 10;
        total += this_digit;

        ++exponent;
        digits.pop();
    }

    return total;
}

(I know it doesn't handle overflow.)

(I know someone will probably say something about the magic numbers.)

(I tried pow(10, exponent) and got incorrect results. I'm guessing because of floating point arithmetic, but not sure why because all the numbers are integers.)


Solution

  • I found lots of information on this page: http://www.kumobius.com/2013/08/c-string-to-int/

    As Galik said, std::stringstream is very slow compared to everything else.

    std::stoi is much faster than std::stringstream

    The manual code can be faster still, but as has been pointed out, it doesn't do all the error checking and could have problems.

    This website also has an improvement over the code above, multiplying the total by 10, instead of the digit before it's added to the total (in sequential order, instead of reverse, with the stack). This makes for less multiplying by 10.

    int Foo_Class::read_int()
    {
        /** reads an integer out of the expression from the cursor */
    
        int to_return = 0;
    
        while (isdigit(expression[cursor]))  // this is safe, returns false, for the end of the string (ISO/IEC 14882:2011 21.4.5)
        {
            to_return *= 10;
            to_return += (expression[cursor] - '0');  // convert from ascii
            ++cursor;
        }
    
        return to_return;
    }