istringstream Conversion Question

M

Mike Copeland

I am using istringstring to convert data. For example,

int parseInt(string source, int start, int length)
{
int iResult;
if((start >= 0) && (start < source.length()))
{
istringstream myStream(source.substr(start, length));
myStream >> iResult;
}
return iResult;
}

where (hopefully) the parameters are valid. In my testing, I find that
if the parameters are NOT valid (start < 0 or > source.length()) or if
the data in source isn't numeric, the code either skips the conversion
(as it should) or the conversion fails. In those cases, the function's
return value is -858993460, which I gather is the unitialized value of
the integer variable iResult.
That's okay to a degree, but I'd like to be able to determine that an
error has occurred - and test for it in the calling logic. I can't find
any definition value for this default value, so I don't the
value/constant to test for, etc.
Given that atoi returns 0 for such errors, and given that I'd like a
more robust way of detecting errors (0 could be a legitimate conversion
result), I'd like to know what better solutions are available. Please
advise. TIA
 
L

LR

Mike said:
I am using istringstring to convert data. For example,

int parseInt(string source, int start, int length)
{
int iResult;
if((start >= 0) && (start < source.length()))
{
istringstream myStream(source.substr(start, length));
myStream >> iResult;
}
return iResult;
}

where (hopefully) the parameters are valid. In my testing, I find that
if the parameters are NOT valid (start < 0 or > source.length()) or if
the data in source isn't numeric, the code either skips the conversion
(as it should) or the conversion fails. In those cases, the function's
return value is -858993460, which I gather is the unitialized value of
the integer variable iResult.

That's probably something specific to your system. I think thats
probably 0xCCCCCCCC. I suspect you are using a version of MS VS,
That's okay to a degree, but I'd like to be able to determine that an
error has occurred - and test for it in the calling logic. I can't find
any definition value for this default value, so I don't the
value/constant to test for, etc.

I don't think you should check for that value. I suspect that you are
building a debug version of your program and if you ever switch to
release you may find that the int is initialized to a different probably
less predictable value.

IMHO it's almost always a good idea to initialize variables.

Given that atoi returns 0 for such errors, and given that I'd like a
more robust way of detecting errors (0 could be a legitimate conversion
result), I'd like to know what better solutions are available. Please
advise. TIA

It's difficult to answer because I don't know what values are possible
in your code.

One solution might be to throw if the conversion doesn't work, something
like:

if(!(myStream >> iResult))
throw SomeType();

Another might be to return a pair with the result and a flag, something
like:

const bool flag = (myStream >> iResult);
return std::make_pair(flag,iResult);

Or you might want to return some known "bad" value if you failed,
perhaps something like:
int t = 0;
const int iResult =
(myStream >> t) ? t : std::numeric_limits<int>::min();


I haven't tested any of these, so please be careful.



LR
 
S

Sousuke

   I am using istringstring to convert data.  For example,

int parseInt(string source, int start, int length)
{
    int  iResult;
    if((start >= 0) && (start < source.length()))
    {
        istringstream myStream(source.substr(start, length));
        myStream >> iResult;
    }
    return iResult;

}

where (hopefully) the parameters are valid.  In my testing, I find that
if the parameters are NOT valid (start < 0 or > source.length()) or if
the data in source isn't numeric, the code either skips the conversion
(as it should) or the conversion fails.  In those cases, the function's
return value is -858993460, which I gather is the unitialized value of
the integer variable iResult.
   That's okay to a degree, but I'd like to be able to determine that an
error has occurred - and test for it in the calling logic.  I can't find
any definition value for this default value, so I don't the
value/constant to test for, etc.
   Given that atoi returns 0 for such errors, and given that I'd like a
more robust way of detecting errors (0 could be a legitimate conversion
result), I'd like to know what better solutions are available.  Please
advise.  TIA

The function is rather pointless. If someone wants to use string
streams to parse stuff, they should just do so directly.

Still, an improved version would be:

bool parseInt(const string& source, int start, int length, int&
result)
{
assert(start >= 0 && start < source.length());

istringstream myStream(source.substr(start, length));
myStream >> result;

return myStream.good();
}

If you want full control over the conversion and more detailed error
reporting, you should write your own function. Here's something I
wrote some time ago:

#include <string>
#include <exception>
#include <limits>
#include <assert.h>

class Integer
{
public:
static const int ALLOW_LEADING_WHITESPACE = 0x1;
static const int ALLOW_LEADING_SIGN = 0x2;

static const int ALL =
ALLOW_LEADING_WHITESPACE |
ALLOW_LEADING_SIGN
;

class OverflowException : public std::exception {};
class FormatException : public std::exception {};

template<class SignedInt>
static SignedInt ParseSigned(
const std::string& text,
std::string::const_iterator* endOfNumber = 0,
int base = 10,
int flags = 0
);
};

template<class SignedInt>
SignedInt Integer::parseSigned(
const std::string& text,
std::string::const_iterator* endOfNumber,
int base,
int flags
)
{
using namespace std;

static_assert(numeric_limits<SignedInt>::is_specialized,
"numeric_limits<SignedInt> must be specialized");
static_assert(numeric_limits<SignedInt>::is_integer, "SignedInt must
be an integer type");
static_assert(numeric_limits<SignedInt>::is_signed, "SignedInt must
be a signed integer type");

assert(base >= 2 && base <= 36);

if (text.empty())
throw FormatException();

string::const_iterator iter = text.begin();

if (flags & ALLOW_LEADING_WHITESPACE)
{
static const char whitespace[] = " \f\n\r\t\v";
string::size_type i = text.find_first_not_of(whitespace);
if (i == string::npos)
throw FormatException();
iter += i;
}

bool isNegative = false;
if (flags & ALLOW_LEADING_SIGN)
{
if (*iter == '+')
{
++iter;
if (iter == text.end())
throw FormatException();
}
else if (*iter == '-')
{
isNegative = true;
++iter;
if (iter == text.end())
throw FormatException();
}
}

const string::const_iterator startOfNumber = iter;
SignedInt result = 0;
if (isNegative)
{
do
{
int digit;
if (*iter >= '0' && *iter <= '9')
digit = *iter - '0';
else if (*iter >= 'a' && *iter <= 'z')
digit = *iter - 'a' + 10;
else if (*iter >= 'A' && *iter <= 'Z')
digit = *iter - 'A' + 10;
else
break;

if (digit >= base)
break;

SignedInt next = result * base - digit;
if (next > result)
throw OverflowException();
result = next;

++iter;
}
while (iter != text.end());
}
else
{
do
{
int digit;
if (*iter >= '0' && *iter <= '9')
digit = *iter - '0';
else if (*iter >= 'a' && *iter <= 'z')
digit = *iter - 'a' + 10;
else if (*iter >= 'A' && *iter <= 'Z')
digit = *iter - 'A' + 10;
else
break;

if (digit >= base)
break;

SignedInt next = result * base + digit;
if (next < result)
throw OverflowException();
result = next;

++iter;
}
while (iter != text.end());
}

if (iter == startOfNumber)
throw FormatException();

if (endOfNumber)
*endOfNumber = iter;

return result;
}

(I was thinking about also writing a ParseUnsigned, but I never
actually needed it.)
 
I

Ian Collins

I am using istringstring to convert data. For example,

int parseInt(string source, int start, int length)
{
int iResult;
if((start>= 0)&& (start< source.length()))
{
istringstream myStream(source.substr(start, length));
myStream>> iResult;
}
return iResult;
}

where (hopefully) the parameters are valid. In my testing, I find that
if the parameters are NOT valid (start< 0 or> source.length()) or if
the data in source isn't numeric, the code either skips the conversion
(as it should) or the conversion fails. In those cases, the function's
return value is -858993460, which I gather is the unitialized value of
the integer variable iResult.
That's okay to a degree, but I'd like to be able to determine that an
error has occurred - and test for it in the calling logic. I can't find
any definition value for this default value, so I don't the
value/constant to test for, etc.
Given that atoi returns 0 for such errors, and given that I'd like a
more robust way of detecting errors (0 could be a legitimate conversion
result), I'd like to know what better solutions are available. Please
advise. TIA

1) Why "iResult" and not simply result?

2) Your input stream is a const, declare it as one.

3) atoi is pretty useless even for a C function. It has no way to
report an error. strtol is a better function to study, it sets errno on
error. The C++ way would be to throw an exception.
 
J

James Kanze

Copying the uninitialized value of iResult is undefined
behavior. You might get anything, including a core dump.
1) Why "iResult" and not simply result?
2) Your input stream is a const, declare it as one.

Not sure I follow you here. You can't read from a const stream.

If you meant the input argument, he's using pass by value, so
the const is less important.
3) atoi is pretty useless even for a C function. It has no
way to report an error. strtol is a better function to study,
it sets errno on error. The C++ way would be to throw an
exception.

Or to return a Fallible---most input errors are best handled by
a return code.
 
I

Ian Collins

Copying the uninitialized value of iResult is undefined
behavior. You might get anything, including a core dump.




Not sure I follow you here. You can't read from a const stream.
s/stream/string/

If you meant the input argument, he's using pass by value, so
the const is less important.

True, I was going to suggest pass by const reference.
Or to return a Fallible---most input errors are best handled by
a return code.

True, I guess I was replying in the context of his earlier post
concerning reading from a file.
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Staff online

Members online

Forum statistics

Threads
473,769
Messages
2,569,577
Members
45,054
Latest member
LucyCarper

Latest Threads

Top