I need a self defined extractor (operator>>) to read a specific string into my own datatype.
The problem is that the requirements for the string are large.
Hence the easiest way is probably to read the whole string from the istream and then check if all requirements are fulfilled.
My Problem is if the string is not valid. Up to my knowledge it is common in C++ that the stream is unchanged.
What is best practice to recover the istream in this case? Is the exception handling in the following example enough?
std::istream& operator>>(std::istream& is, Foo& f)
{
std::string str;
if (is >> str)
{
// check if string is valid
if ( is_valid( str ) )
{
// set new values in f
}
else
{
// recover stream
std::for_each(str.rbegin(), str.rend(),
[&] (char c)
{
is.putback(c);
});
// ste failbit
is.clear(std::ios_base::failbit);
}
}
return is;
}
And what about std::getline() instead of is >> str ? Are there other pitfalls?
Thanks
Marco
You can't get streams back to the initial position where you started reading, at least not in general. In theory, you can put back characters or seek to a location where you had been before but many stream buffers don't support putting back characters or seeking. The standard library gives some limited guidance but it deals with rather simple types, e.g., integers: the characters are read as long as the format matches and it stops just there. Even if the format matches, there may be some errors which could have been detected earlier.
Here is a test program demonstrating the standard library behavior:
Just to explain the four test cases:
'-'
character.int
using octal numbers. The failure could have been detected upon the character'8'
but both the'8'
and the'9'
are consumed and the input fails.Based on that, I'd think there wouldn't be an expectation to reset the stream to the original position when semantics checks on a well-formed input fail.