Say I have a class with two data members:
class X {
std::string a;
int b;
public:
ostream& print(ostream& os);
istream& read(istream& is);
}
The print
function outputs all of the data nicely formatted, like so:
ostream& X::print(ostream& os) {
return os << a << ' ' << b;
}
Now, the read
function is supposed to do the inverse: read something in a specified format (say, like horse 54
which would then result in a = "horse"
and b = 54
).
So say an input does not follow this format. My intuition says that as soon as we encounter an unexpected character (for example a letter when trying to read an int
), we set the failbit
and put every character we read so far back into the stream. What is the expected behavior of a read
function (or operator>>
) in this case? How does the standard library behave? Should we be required to undo all extraction of characters if the read fails?
In general in case of failure you're expected to leave any object involved into a valid state. Whether that means rolling back the variable being written to, partially writing to it or anything else depends on what you are trying to accomplish and what you think is going to be best for the user. In any case, be sure to document your choice so that users can program knowing how your implementation will behave.
As Anton already said, the standard library does not seem to make any effort into putting characters back into the stream. Another practical example, which seems to be closer to what you are doing, is operator>>
for the std::complex
class, which actually has to read multiple tokens in a sequence before being done.
template<typename _Tp, typename _CharT, class _Traits>
basic_istream<_CharT, _Traits>&
operator>>(basic_istream<_CharT, _Traits>& __is, complex<_Tp>& __x)
{
_Tp __re_x, __im_x;
_CharT __ch;
__is >> __ch;
if (__ch == '(')
{
__is >> __re_x >> __ch;
if (__ch == ',')
{
__is >> __im_x >> __ch;
if (__ch == ')')
__x = complex<_Tp>(__re_x, __im_x);
else
__is.setstate(ios_base::failbit);
}
else if (__ch == ')')
__x = __re_x;
else
__is.setstate(ios_base::failbit);
}
else
{
__is.putback(__ch);
__is >> __re_x;
__x = __re_x;
}
return __is;
}