假设我有一个包含两个数据成员的类:
class X {
std::string a;
int b;
public:
ostream& print(ostream& os);
istream& read(istream& is);
}
print
函数输出所有格式良好的数据,如下所示:
ostream& X::print(ostream& os) {
return os << a << ' ' << b;
}
现在,read
函数应该执行相反的操作:以指定格式读取内容(例如,如horse 54
,然后会生成a = "horse"
和b = 54
)。
所以说输入不遵循这种格式。我的直觉说,一旦我们遇到意外的角色(例如在尝试阅读int
时写了一封信),我们就设置failbit
和将我们读到的每个角色放回到目前为止流。在这种情况下,read
函数(或operator>>
)的预期行为是什么?标准库如何表现?如果读取失败,我们是否应该要求撤消所有字符提取?
答案 0 :(得分:1)
标准库从不尝试在出现错误时将字符放回流中。例如,以下是关于如何从流(short
)中读取27.7.2.2.2/2
的标准的摘录:
operator>>(short& val);
转换发生时好像由以下代码片段执行(使用与前面代码片段相同的表示法):
typedef num_get<charT,istreambuf_iterator<charT,traits> > numget;
iostate err = ios_base::goodbit;
long lval;
use_facet<numget>(loc).get(*this, 0, *this, err, lval);
if (lval < numeric_limits<short>::min()) {
err |= ios_base::failbit;
val = numeric_limits<short>::min();
} else if (numeric_limits<short>::max() < lval) {
err |= ios_base::failbit;
val = numeric_limits<short>::max();
} else
val = static_cast<short>(lval);
setstate(err);
您会看到,即使该号码不适合short
,也不会有任何回复。
答案 1 :(得分:1)
一般情况下,如果失败,您应该将任何涉及的对象留在有效状态。这是否意味着回滚正在写入的变量,部分写入或其他任何内容取决于您要完成的内容以及您认为最适合用户的内容。在任何情况下,请务必记录您的选择,以便用户可以编程了解您的实施将如何表现。
正如Anton所说,标准库似乎没有做任何努力将字符放回流中。另一个实际例子似乎更接近你正在做的事情,operator>>
类是std::complex
,它实际上必须在完成之前读取序列中的多个标记。
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;
}