Home > Software engineering >  stringstream operator>> fails to assign a number in debug
stringstream operator>> fails to assign a number in debug

Time:11-04

I have this simple function that, given a string str, if it is a number then return 'true' and overwrite the reference input num.

template <typename T>
bool toNumber(string str, T& num)
{
    bool bRet = false;
    if(str.length() > 0U)
    {
        if (str == "0")
        {
            num = static_cast<T>(0);
            bRet = true;
        }
        else
        {
            std::stringstream ss;
            ss << str;
            ss >> num;    // if str is not a number op>> it will assign 0 to num
            if (num == static_cast<T>(0)) 
            {
                bRet = false;
            }
            else
            {
                bRet = true;
            }
        }
    }
    else
    {
        bRet = false;
    }
    return bRet;
}

So I expect that:

int x, y;
toNumber("90", x); // return true and x is 90
toNumber("New York", y); // return false and let y unasigned.

On my machine, both debug and release configurations works fine, but on the server, only with the debug configuration, in calls like toNumber("New York", y) the 'ss >> num' fails to recognize that str is a string.

I checked the project configuration, but they are the same for both machines (the server is a svn-checkout of my local vs-2015 project).

I have literally no idea on how to solve the problem. Can anyone help me with this?

CodePudding user response:

Checking the value of the number that operator>> outputs is the wrong way to go. You should check the stringstream's failure state instead, eg:

template <typename T>
bool toNumber(string str, T& num)
{
    bool bRet = false;
    if (str.length() > 0U)
    {
        if (str == "0")
        {
            num = static_cast<T>(0);
            bRet = true;
        }
        else
        {
            std::stringstream ss;
            ss << str;
            if (ss >> num) // <--
            {
                bRet = true;
            }
            else
            {
                bRet = false;
            }
        }
    }
    else
    {
        bRet = false;
    }
    return bRet;
}

operator>> returns a reference to the input stream, and the stream is implicitly convertible to bool in boolean contexts, like an if statement, where true means the stream is in a good state, and false means the stream is in a failed state.

In which case, you can greatly simplify the function much much further, by getting rid of the redundant bRet assignments, and the redundant input checks that the stringstream will already handle for you, eg:

template <typename T>
bool toNumber(const string &str, T& num)
{
    std::istringstream ss(str);
    return static_cast<bool>(ss >> num);
    // or:
    // return !!(ss >> num);
}

Online Demo

CodePudding user response:

Your code is made too complicated, you can simplify it to this:

template <typename T>
bool toNumber(std::string str, T& num)
{
    return !!(std::istringstream { std::move(str) } >> num);
}

https://godbolt.org/z/Pq5xGdof5

Ok I've missed that you wish to avoid zero assignment in case of failure (what streams do by default):

template <typename T>
bool toNumber(std::string str, T& num)
{
    T tmp;
    std::istringstream stream{ std::move(str) };
    if (stream >> tmp) {
        num = tmp;
    }
    return !!stream;
}

https://godbolt.org/z/nErqn3YYG

CodePudding user response:

if (num == static_cast<T>(0))

Bad idea. To know if operator>> failed, check the status of the stream.

if (ss >> num) { ...

Once you have this check in place, the (totally incorrect) piece

    if (str == "0")
    {
        num = static_cast<T>(0);
        bRet = true;
    }

becomes redundant, and

if(str.length() > 0U)

also becomes redundant, and then the whole thing simplifies to a line or two.

  • Related